Codeforces-669E:Little Artem and Time Machine(CDQ分治)

链接:http://codeforces.com/problemset/problem/669/E

 题意:三种操作:1 x y  在第x秒y点的值+1.

                              2 x y  在第x秒y点的值-1

                              3 x y  查询在x秒y点处的值

思路:因为操作 1 2 3 并不是按照x从小到大的顺序给出的。所以无法简单的利用树状数组。仔细观察可以发现这些操作满足三维偏序(操作顺序,操作时间,操作种类)。

其中操作顺序已排好序,我们要按操作顺序执行各个操作并完成查询。

于是可以利用CDQ分治,分治时分别对左半区间和右半区间的第二维即操作时间排序,按时间顺序将左半区间的操作影响(即y点+1或-1)添加到右半区间的查询操作上,更新了查询结果的同时又不影响操作顺序。

#include
using namespace std;
const int MAX=1e5+10;
struct lenka
{
    int op,t,x,id,pos;//pos记录y点离散化排序后的位置
}A[MAX];
int cmp(const lenka& p,const lenka&q){return p.tv;         //将所有的y点离散化
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=(l+r)/2;
    cdq(l,mid);
    cdq(mid+1,r);
    sort(A+l,A+mid+1,cmp);
    sort(A+mid+1,A+r+1,cmp);
    int j=l;
    for(int i=mid+1;i<=r;i++)
    {
        while(j<=mid&&A[j].t<=A[i].t)
        {
            num[A[j].pos]+=A[j].op;
            j++;
        }
        if(A[i].op==0)ans[A[i].id]+=num[A[i].pos];
    }
    for(int i=l;i>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&A[i].op,&A[i].t,&A[i].x);
        if(A[i].op==2)A[i].op=-1;
        if(A[i].op==3)A[i].op=0;
        A[i].id=i;
        v.push_back(A[i].x);
    }
    //将所有的y点离散化
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    for(int i=1;i<=n;i++)A[i].pos=lower_bound(v.begin(),v.end(),A[i].x)-v.begin()+1;
    cdq(1,n);
    sort(A+1,A+n+1,cmp1);
    for(int i=1;i<=n;i++)if(A[i].op==0)printf("%d\n",ans[i]);
    return 0;
}

 

你可能感兴趣的:(分治)