离散化

我的很长,你算一下

收藏本题

提交记录

题目描述

小e有一个很长很长的数组,数组的下标范围为[0,10^9][0,109],初始时每个元素均为00。

现在,他想进行nn次操作,每次操作将某个下标ii处的元素加上xx

然后他给出了qq次询问,每个询问格式为l\ rl r,你需要回答出下标在区间[l,r][l,r]内的所有元素的和。

输入描述

第一行:两个整数q,n,*。(1<=n,q<=1e5)

接下来n行:每行两个整数i,x。(0<=i<=1e9,0<=x1e4)

再接下q行:每行两个整数l,r*。(1<=l<=r<=1e9)

输出描述

共qq行,每行输出相应询问的答案。

输入样例1

4 2
0 2 
3 3
1 5
0 1
0 1
1 3

输出样例1

8
8

上面的题目是离散化的典型题目,这样的的题目的特点就是整个数组的大小远远大于我们的操作次数,所以我们要是对于整个数组进行遍历的话会超时,所以我们将每次的操作储存起来我们,然后二分查找对于的操作,利用前缀和进行求部分和,来实现对于数的定点加和求部分和。

同时这种我们先将数据储存在进行查询和处理的方式叫做离线

而我们正常使用的叫做在线

下面为AC代码

#include<bits/stdc++.h>
using namespace std;
#define int long long

const int N = 3e5+9;
int a[N],l[N],r[N];
stack<int> stk;
vector<int> X;
struct Q{
    int a,b;
}add[N],que[N];
int getidx(int x){
    //通过lower_bound 的二分查找第一个大于等于的的元素的迭代器
    //返回值范围为[1,X.size()]
    return lower_bound(X.begin(),X.end(),x)-X.begin()+1;
}
void solve(){
    //离散化
    int n,q;
    cin>>n>>q;
    for(int i = 1;i<=n;i++){
        int x,w;
        cin>>x>>w;
        X.push_back(x),X.push_back(x);
        add[i] = {x,w};
    }
    for(int i = 1;i<=q;i++){
        int l,r;cin>>l>>r;
        X.push_back(l),X.push_back(r);
        que[i] = {l,r};
    }
    //排序并进行去重操作
    sort(X.begin(),X.end());
    X.erase(unique(X.begin(),X.end()),X.end());
    for(int i = 1;i<=n;i++){
        int x,w;
        x = getidx(add[i].a);
        w = add[i].b;
        a[x] += w;
    }
    for(int i = 1;i<=X.size();i++) a[i] += a[i-1];
    for(int i = 1;i<=q;i++){
        int x,w;
        x = getidx(que[i].a);
        w = getidx(que[i].b);
//      auto [x,w] = {getidx(que[i].a),getidx(que[i].b)};
        cout<<a[w]-a[x-1]<<'\n';
    }
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int _ = 1;
    while(_--)solve();
    return 0;
}