Mokia
分析
很明显可以用树状数组做,但数据范围明显不允许,是开不下二维数组的
\[\huge那如何是好呢?
\]
这里就需要分治了,这里用的是 \(CDQ\) 分治,它的思路也是非常版,就一个递归函数,
它一共有三个需要干的
-
1 找到范围中点 \(mid\) ,递归解决 \((l,mid)\)
-
2 递归解决 \((mid+1,r)\)
-
3 找出 \(mid\) 左边的修改对 \(mid\) 右面的查询的影响
对于二维坐标和操作,可操作的东西有三个,操作顺序,\(x\) 坐标,\(y\) 坐标
而有影响的修改操作只能是顺序在其之后,横纵坐标比其大的查询————三维偏序
剩下的就是二位前缀和和套版子了
solusion
点击查看代码
#include<bits/stdc++.h>
const int maxn=2e5+1e4;
using namespace std;
int n,k,cnt,c[maxn],dfn,vis[maxn],ans[maxn],t;
struct lsx{int t,x,y,z,opt,time;}q[maxn],a[maxn];
bool cmp(lsx a,lsx b)
{
return a.x!=b.x?a.x<b.x:(a.y!=b.y?a.y<b.y:(a.t!=b.t?a.t<b.t:a.z>b.z));
}
int lowbit(int x){return x&-x;}
void add(int x,int y)
{
while(x<=t)
{
if(vis[x]!=dfn) vis[x]=dfn,c[x]=0;
c[x]+=y;
x+=lowbit(x);
}
}
int query(int x)
{
int temp=0;
while(x)
{
if(vis[x]==dfn)temp+=c[x];
x-=lowbit(x);
}
return temp;
}
void cdq(int l,int r)
{
if(l==r) return;
int mid=l+r>>1;
cdq(l,mid),cdq(mid+1,r);
dfn++;
int ll=l,rr=mid+1;
for(int i=l;i<=r;i++)
{
if(ll<=mid&&q[ll].y<=q[rr].y||rr>r)
{
if(!q[ll].opt)
{
add(q[ll].t,q[ll].z);
}
a[i]=q[ll++];
}
else
{
int temp=0;
if(q[rr].opt!=0)
{
temp=query(q[rr].t);
// cout<<q[rr].opt<<" "<<temp<<endl;
ans[q[rr].time]+=q[rr].opt*temp;
}
a[i]=q[rr++];
}
}
for(int i=l;i<=r;i++) q[i]=a[i];
}
int main()
{
int qcnt=0;
int x,y,z,h;
scanf("%d%d",&x,&n);
n++;
while(1)
{
scanf("%d",&x);
if(x==3) break;
if(x==1)
{
scanf("%d%d%d",&x,&y,&z);
x++,y++;
++cnt;t++;
q[cnt]={t,x,y,z,0,0};
}
else
{
scanf("%d%d%d%d",&x,&y,&z,&h);
x++,y++,z++,h++;
++cnt;
q[cnt]=(lsx){t,z,h,0,1,++qcnt};
++cnt;
q[cnt]=(lsx){t,z,y-1,0,-1,qcnt};
++cnt;
q[cnt]=(lsx){t,x-1,h,0,-1,qcnt};
++cnt;
q[cnt]=(lsx){t,x-1,y-1,0,1,qcnt};
}
}
sort(q+1,q+cnt+1,cmp);
cdq(1,cnt);
for(int i=1;i<=qcnt;i++) printf("%d\n",ans[i]);
return 0;
}
/*
0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
*/