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;
}