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

posted @ 2020-01-19 14:25  dz_ice  阅读(124)  评论(0编辑  收藏  举报