[BOI2007]Mokia题解
这几天学习了cdq分治,来写一篇文章加深理解
一开始看到这道题,我会二维树状数组!
w<=2000000
可惜过不得
然后我们就可以往cdq分治偏序类的问题上想,但我们还要用类似于二维前缀和的方式维护一下,把每一次询问拆成\(sum[x_2][y_2]-sum[x_1-1][y_2]-sum[x_2][y_1-1]+sum[x_1-1][y_1-1]\),分为四个\(ask()\),然后就是三位偏序的模板了,数据由于是按时间顺序给的,所以只要归并搞\(x\)坐标,然后树状数组搞\(y\)坐标,每次统计一下即可
放一下代码
#include<bits/stdc++.h>
using namespace std;
struct node
{
int xx,yy,nu,s,qsu;
}a[1000003],p1[1000003];
int m,n,tr[2000003],xxx,yyy,xx1,yy1,qsum,ans[200003],typ;
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int num)
{
for(int i=x;i<=n;i+=lowbit(i))
tr[i]+=num;
}
int ask(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
sum+=tr[i];
return sum;
}
void cdq(int l,int r)
{
if(l==r)
return;
int mid=(l+r)/2,p=l,q=mid+1,tot=l-1;
cdq(l,mid),cdq(mid+1,r);
while(p<=mid&&q<=r)
{
if(a[p].xx<=a[q].xx)
{
if(a[p].s==0)
add(a[p].yy,a[p].nu);
tot++,p1[tot]=a[p],p++;
}
else
{
if(a[q].s!=0)
ans[a[q].qsu]+=a[q].s*ask(a[q].yy);
tot++,p1[tot]=a[q],q++;
}
}
while(p<=mid)
{
if(a[p].s==0)
add(a[p].yy,a[p].nu);
tot++,p1[tot]=a[p],p++;
}
while(q<=r)
{
if(a[q].s!=0)
ans[a[q].qsu]+=a[q].s*ask(a[q].yy);
tot++,p1[tot]=a[q],q++;
}
for(int i=l;i<=mid;i++)
if(a[i].s==0)
add(a[i].yy,-a[i].nu);
for(int i=l;i<=r;i++)
a[i]=p1[i];
}
int main()
{
scanf("%d%d",&n,&n);
while(1)
{
scanf("%d",&typ);
if(typ==3)
break;
m++;
if(typ==1)
scanf("%d%d%d",&a[m].xx,&a[m].yy,&a[m].nu);
else
{
scanf("%d%d%d%d",&xx1,&yy1,&xxx,&yyy);
qsum++,a[m].xx=xxx,a[m].yy=yyy,a[m].s=1,a[m].qsu=qsum;
a[m+1].xx=xx1-1,a[m+1].yy=yyy,a[m+1].s=-1,a[m+1].qsu=qsum;
a[m+2].xx=xxx,a[m+2].yy=yy1-1,a[m+2].s=-1,a[m+2].qsu=qsum;
a[m+3].xx=xx1-1,a[m+3].yy=yy1-1,a[m+3].s=1,a[m+3].qsu=qsum,m+=3;
}
}
cdq(1,m);
for(int i=1;i<=qsum;i++)
cout<<ans[i]<<endl;
return 0;
}