Acwing 802. 区间和(下标离散化+vector+二分)

地址:https://www.acwing.com/problem/content/description/804/

 

一:

本来想的是差分做,但是范围是不允许开这么大的数组的。l,r<=1e9

所以考虑离散化。

发现n只有1e5,n个加操作,m个L,R,最多用到n+L+R个区间,也就是3e5。所以开这么大就好了。

vector具有去重函数,排序函数,所以考虑用它把所有输入的下标存起来,离散化成对应的vector下标值。

比如:

0    1     2

12  200   10000

下标12,200,10000可以由0,1,2代替。

而对于一个离散前的下标,在vector里寻找时二分即可。

二:

代码思路:

vector<int>alls;   //存所有下标
vector<PII>query,add;  //add存n个操作,x-c。query存m个询问操作:L--R

int a[maxn]; //下标离散后的各个位置的值

int s[maxn];//前缀和

1:n个操作,x,c。alls,add存取

2:m个操作,L,R。alls,query存取

3:alls排序,去重

4:a[]把离散化的下标+c

5:前缀和

6:遍历query里的每一组L-R,找到它们在alls里离散化后的下标,前缀和即可。

#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
const int maxn=3e5+10,maxn2=31*maxn;//maxn·­±¶ 
int n,m;
vector<int>alls;
vector<PII>query,add;
int a[maxn],s[maxn];
int find(int x)
{
    int l=0,r=alls.size()-1;
    while(l<r)
    {
        int md=l+r>>1;
        if(alls[md]>=x)
            r=md;
        else
            l=md+1;
    }
    return r+1;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int x,c;
        cin>>x>>c;
        add.push_back({x,c});
        alls.push_back(x);
    }
    for(int i=1;i<=m;i++)
    {
        int l,r;
        cin>>l>>r;
        query.push_back({l,r});
        alls.push_back(l);
        alls.push_back(r);
    }
    sort(alls.begin(),alls.end());
    alls.erase(unique(alls.begin(),alls.end()),alls.end());
    for(auto item : add)
    {
        int x=find(item.first);
        a[x]+=item.second;
    }
    for(int i=1;i<=alls.size();i++)
    {
        s[i]=s[i-1]+a[i];
    }
    for(auto item : query)
    {
        int l = find(item.first),r=find(item.second);
        cout<<s[r]-s[l-1]<<endl;
    }
}

 

posted @ 2020-11-13 16:40  liyexin  阅读(120)  评论(0编辑  收藏  举报