P3810次元の部分配列(Moの花)
CDQパーティション・テンプレート・タイトル
第一次元直接配列決定、分割統治、フェンウィックツリーと第三の次元を使用して、第2の寸法
#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\n",ans[i]);
return 0;
}
2018SEERCポイントや長方形(洛谷P5873)
問題の意味:
二次元平面、二つの動作:
1つのXY:IN(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\n",res);
}
return 0;
}