CDQ分治模板题

Posted hooying

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CDQ分治模板题相关的知识,希望对你有一定的参考价值。

P3810 三维偏序(陌上花开)

CDQ分治模板题
第一维直接排序,第二维用分治,第三维用树状数组

#include<bits/stdc++.h>
using namespace std;
const int maxx = 1e5+10;
struct node
{
    int a,b,c,w,s;
}e[maxx],g[maxx];
bool cmp(node x,node y)
{
    if(x.a!=y.a)return x.a<y.a;
    if(x.b!=y.b)return x.b<y.b;
    return x.c<y.c;
}
int t[2*maxx],ans[maxx];
int n,m;
void add(int x,int c)
{
    for(int i=x;i<=m;i+=(i&(-i)))t[i]+=c;
}
int getsum(int x)
{
    int res=0;
    for(int i=x;i>0;i-=(i&(-i)))res+=t[i];
    return res;
}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=(l+r)/2;
    cdq(l,mid);cdq(mid+1,r);
    int p=l,q=mid+1,cnt=l;
    while(p<=mid&&q<=r)
    {
        if(e[p].b<=e[q].b)add(e[p].c,e[p].w),g[cnt++]=e[p++];
        else e[q].s+=getsum(e[q].c),g[cnt++]=e[q++];
    }
    while(p<=mid)add(e[p].c,e[p].w),g[cnt++]=e[p++];
    while(q<=r)e[q].s+=getsum(e[q].c),g[cnt++]=e[q++];
    for(int i=l;i<=mid;i++)add(e[i].c,-e[i].w);
    for(int i=l;i<=r;i++)e[i]=g[i];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);
        e[i].w=1;
    }
    sort(e+1,e+1+n,cmp);
    int tot=1;
    for(int i=2;i<=n;i++)
    {
        if(e[i].a==e[tot].a&&e[i].b==e[tot].b&&e[i].c==e[tot].c)e[tot].w++;
        else e[++tot]=e[i];
    }
    cdq(1,tot);
    for(int i=1;i<=tot;i++)ans[e[i].s+e[i].w-1]+=e[i].w;
    for(int i=0;i<n;i++)printf("%d
",ans[i]);
    return 0;
}

2018SEERC Points and Rectangles(洛谷P5873)

题意:
二维平面上,两种操作:
1 x y:在(x,y)放一个点
2 x1,y1,x2,y2:放一个左下角为(x1,y1),右上角为(x2,y2)的矩阵。
每次操作之后要求出 所有矩阵包含的点的数目 的总和。

第一维为操作顺序,第二维为x,第三维为y
分别统计点和矩阵的相互贡献。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxx = 4e5+10;
struct node
{
    int op,x,y,id;
    bool operator < (const node &t)const
    {
        return id<t.id;
    }
}e[maxx],g[maxx];
int a[maxx],t[maxx],ans[maxx];
int tot=0,num=0;
vector<int>v1,v2;
void add(int x,int c)
{
    for(int i=x;i<=num;i+=(i&(-i)))t[i]+=c;
}
int getsum(int x)
{
    int res=0;
    for(int i=x;i>0;i-=(i&(-i)))res+=t[i];
    return res;
}
void cdq1(int l,int r) //点对矩阵贡献
{
    if(l==r)return;
    int mid=(l+r)/2;
    cdq1(l,mid),cdq1(mid+1,r);
    int p=l,q=mid+1,cnt=l;
    while(p<=mid&&q<=r)
    {
        if(e[p].x<=e[q].x)
        {
            if(e[p].op==1)add(e[p].y,1),v1.push_back(e[p].y);
            g[cnt++]=e[p++];
        }
        else
        {
            if(e[q].op==2)ans[e[q].id]+=getsum(e[q].y);
            else if(e[q].op==3)ans[e[q].id]-=getsum(e[q].y);
            g[cnt++]=e[q++];
        }
    }
    while(p<=mid)g[cnt++]=e[p++];
    while(q<=r)
    {
        if(e[q].op==2)ans[e[q].id]+=getsum(e[q].y);
        else if(e[q].op==3)ans[e[q].id]-=getsum(e[q].y);
        g[cnt++]=e[q++];
    }
    for(int i=l;i<=r;i++)e[i]=g[i];
    for(int i=0;i<v1.size();i++)add(v1[i],-1);
    v1.clear();
}
//(x1-1,y1-1),(x1-1,y2),(x2,y1-1),(x2,y2)对应贡献为1,-1,-1,1
void cdq2(int l,int r) //矩阵对点贡献
{
    if(l==r)return;
    int mid=(l+r)/2;
    cdq2(l,mid),cdq2(mid+1,r);
    int p=l,q=mid+1,cnt=l;
    while(p<=mid&&q<=r)
    {
        if(e[p].x<e[q].x)
        {
            if(e[p].op==2)add(e[p].y,1),v1.push_back(e[p].y);
            else if(e[p].op==3)add(e[p].y,-1),v2.push_back(e[p].y);
            g[cnt++]=e[p++];
        }
        else
        {
            if(e[q].op==1)ans[e[q].id]+=getsum(e[q].y-1);  //注意这里要减1
            g[cnt++]=e[q++];
        }
    }
    while(p<=mid)g[cnt++]=e[p++];
    while(q<=r)
    {
        if(e[q].op==1)ans[e[q].id]+=getsum(e[q].y-1);
        g[cnt++]=e[q++];
    }
    for(int i=l;i<=r;i++)e[i]=g[i];
    for(int i=0;i<v1.size();i++)add(v1[i],-1);
    for(int i=0;i<v2.size();i++)add(v2[i],1);
    v1.clear(),v2.clear();
}
int main()
{
    int n;
    scanf("%d",&n);
    int op,x1,y1,x2,y2;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d",&x1,&y1);
            e[++tot]=node{op,x1,y1,i};
            a[++num]=x1,a[++num]=y1;
        }
        else
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            e[++tot]=node{op,x1-1,y1-1,i};
            e[++tot]=node{op,x2,y2,i};
            e[++tot]=node{op+1,x1-1,y2,i};
            e[++tot]=node{op+1,x2,y1-1,i};
            a[++num]=x1-1,a[++num]=y1-1,a[++num]=x2,a[++num]=y2;
        }
    }
    sort(a+1,a+1+num);
    num=unique(a+1,a+1+num)-a-1;
    for(int i=1;i<=tot;i++)
    {
        e[i].x=lower_bound(a+1,a+1+num,e[i].x)-a;
        e[i].y=lower_bound(a+1,a+1+num,e[i].y)-a;
    }
    cdq1(1,tot);
    sort(e+1,e+1+tot);
    cdq2(1,tot);
    LL res=0;
    for(int i=1;i<=n;i++)
    {
        res+=ans[i];
        printf("%lld
",res);
    }
    return 0;
}

以上是关于CDQ分治模板题的主要内容,如果未能解决你的问题,请参考以下文章

P3810 模板三维偏序(陌上花开)(CDQ分治)

模板:CDQ分治

P3374 模板树状数组 1

CDQ分治总结

bzoj 2683 简单题 cdq分治

P3810 模板三维偏序(陌上花开)(cdq分治)