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
*/



posted @ 2024-07-11 20:08  _君の名は  阅读(22)  评论(2编辑  收藏  举报