【JOISC2020】扫除

【JOISC2020】扫除

Description

由于 Bitaro AK 了 IOI,所以 IOI 主办方送了他一套房子,为一个边长为 N 的等腰直角三角形。房间内一点用坐标 (x,y) 表示,其中 0x+yN。直角顶点为原点,三角形两腰分别为 x 轴与 y 轴。

一天,Bitaro 发现自己已经 AK 了 1919810 届 IOI 闲的没事做准备打扫房间里的灰尘。这些灰尘一开始一共有 M 堆,其中第 i 堆位于 (Xi,Yi)。同时,可能存在多堆灰尘位于同一个位置上的情况。

现在 Bitaro 准备用扫帚打扫房间。我们认为扫帚是放置在房间里的一条线段,并且将这条线段的长度称为扫帚的宽度。由于 Bitaro 很有条理,所以他只会用以下的两种方式打扫房间:

  • Bitaro 将扫帚平行于 x 轴放置,一端位于原点。然后他会水平向上移动扫帚,直到不能移动为止。如果扫帚的宽度为 l,那么原来一堆满足 x<Nl,yl 的灰尘 (x,y) 将会被移动到 (Nl,y)。(这个位置可能会存在多堆灰尘)我们称这个过程为过程 H。

  • Bitaro 将扫帚平行于 y 轴放置,一端位于原点。然后他会垂直向右移动扫帚,直到不能移动为止。如果扫帚的宽度为 l,那么原来一堆满足 xl,y<Nl 的灰尘 (x,y) 将会被移动到 (x,Nl)。(这个位置可能会存在多堆灰尘)我们称这个过程为过程 V。

在 Bitaro 的房间里,依次会发生 Q 个事件。第 i 个事件形如以下 4 种:

  • Bitaro 想要计算第 Pi 堆灰尘的位置坐标;

  • Bitaro 使用宽度为 Li 的扫帚,进行了过程 H;

  • Bitaro 使用宽度为 Li 的扫帚,进行了过程 V;

  • 有一堆新的灰尘出现在点 (Ai,Bi) 处。如果在这个事件之前一共有 c 堆灰尘,那么这堆灰尘就是房间中的第 c+1 堆灰尘。

由于 Bitaro 已经 AK 了 IOI,啥都不想干,所以你需要写一个程序,给出房间的腰长,每一堆灰尘的位置坐标和每个事件的细节,求出要求的某堆灰尘的位置坐标。

Input

第一行三个整数,分别为 N,M,Q

接下来 m 行,每行两个整数 Xi,Yi,表示第 i 堆灰尘一开始的位置。

接下来 Q 行,每行两到三个整数,表示一个事件。设 Ti 为第一个整数,每行含义如下:

  • 如果 Ti=1,则这行有两个整数 Ti,Pi,表示 Bitaro 要计算第 Pi 堆灰尘的坐标;

  • 如果 Ti=2,则这行有两个整数 Ti,Li,表示 Bitaro 用宽度为 Li 的扫帚进行了过程 H;

  • 如果 Ti=3,则这行有两个整数 Ti,Li,表示 Bitaro 用宽度为 Li 的扫帚进行了过程 V;

  • 如果 Ti=4,则这行有三个整数 Ti,Ai,Bi,表示一堆新的灰尘出现在 (Ai,Bi) 位置。

Output

对于每个 Ti=1 的事件,输出一行两个整数,表示事件 i 发生时第 Pi 堆灰尘的位置坐标。

Sample Input

6 2 10
1 1
4 0
4 2 3
3 3
1 1
4 1 2
2 3
2 0
1 4
3 2
1 3
1 2

Sample Output

1 3
3 2
3 3
6 0

Data Constraint

对于 100% 的数据,1n109,1m5×105,1Q106。保证:

  • 0Xi,YiN,Xi+YiN(1im)

  • 1PiM(1iQ),其中 M 表示事件 i 发生时灰尘的堆数;

  • 0Lin1(1iQ)

  • 0Ai,Bin,Ai+Bin(1iQ)

  • 至少存在一个 Ti=1 的事件。

Solution

可以从最简单的情况入手

假设只有一种修改,所有询问在修改后,同时没有插入点

显然只要在线段树上改一改扫一扫就行了

现在考虑有两种修改

可以发现的是 V 和 H 可以互相影响,但 V 操作内部独立,H 操作同理

然后考虑求出每个操作所影响的最小坐标p

显然一个 V 会让[p,nl1]内的 H maxl+1

可以线段树维护

最后考虑插入

很容易可以求出一个询问所用的修改区间

所以直接线段树分治就行了

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define N 1000010
#define M 20000000

int n,m,q,vis[N],lst[N],oph[N],opv[N],c1,c2,cnt;
struct point{int x,y,num;}p[N],val[N],a[N],s1[N],s2[N];
int ls[M],rs[M],tag[M],tot;
struct tree{
	int root;
	void ul(int x){if(!ls[x])ls[x]=++tot;}
	void ur(int x){if(!rs[x])rs[x]=++tot;}
	void change(int x,int l,int r,int ll,int rr,int v){
		if(r<ll||l>rr)return;
		if(l>=ll&&r<=rr){tag[x]=max(tag[x],v);return;}
		int mid=l+r>>1;
		ul(x);change(ls[x],l,mid,ll,rr,v);
		ur(x);change(rs[x],mid+1,r,ll,rr,v);
	}
	int query(int x,int l,int r,int pos){
		if(!x)return 0;
		if(l==r)return tag[x];
		int mid=l+r>>1;
		return max(tag[x],pos<=mid?query(ls[x],l,mid,pos):query(rs[x],mid+1,r,pos));
	}
	void build(){root=++tot;}
}t[2];
bool cmp1(point x,point y){return x.x<y.x;}
bool cmp2(point x,point y){return x.y<y.y;}
struct Divide{
	#define Ls x<<1
	#define Rs (x<<1)|1
	vector<int>ask[N*4];
	void insert(int x,int l,int r,int ll,int rr,int id){
		if(r<ll||l>rr)return;
		if(l>=ll&&r<=rr){ask[x].push_back(id);return;}
		int mid=l+r>>1;
		insert(Ls,l,mid,ll,rr,id);insert(Rs,mid+1,r,ll,rr,id);
	}
	void solve(int x,int l,int r){
		int h;
		t[0].build();t[1].build();
		c1=c2=0;
		F(i,l,r){
			if(oph[i]!=-1){
				int tmp=t[0].query(t[0].root,0,n,oph[i]);
				s1[++c1]=(point){tmp,oph[i],n-oph[i]};
				t[1].change(t[1].root,0,n,tmp,n-oph[i]-1,oph[i]+1);
			}
			if(opv[i]!=-1){
				int tmp=t[1].query(t[1].root,0,n,opv[i]);
				s2[++c2]=(point){tmp,opv[i],n-opv[i]};
				t[0].change(t[0].root,0,n,tmp,n-opv[i]-1,opv[i]+1);
			}
		}
		F(i,1,tot)tag[i]=ls[i]=rs[i]=0;
		tot=0;
		t[0].build();t[1].build();
		cnt=0;
		for(auto d:ask[x])a[++cnt]=val[d];
		sort(s1+1,s1+c1+1,cmp1);
		sort(a+1,a+cnt+1,cmp1);
		h=0;
		F(i,1,cnt){
			while(s1[h+1].x<=a[i].x&&h+1<=c1){
				h++;
				t[0].change(t[0].root,0,n,0,s1[h].y,s1[h].num);
			}
			int Q=t[0].query(t[0].root,0,n,a[i].y);
			val[a[i].num].x=max(val[a[i].num].x,Q);
		}
		sort(s2+1,s2+c2+1,cmp1);
		sort(a+1,a+cnt+1,cmp2);
		h=0;
		F(i,1,cnt){
			while(s2[h+1].x<=a[i].y&&h+1<=c2){
				h++;
				t[1].change(t[1].root,0,n,0,s2[h].y,s2[h].num);
			}
			int Q=t[1].query(t[1].root,0,n,a[i].x);
			val[a[i].num].y=max(val[a[i].num].y,Q);
		}
		F(i,1,tot)tag[i]=ls[i]=rs[i]=0;
		tot=0;
		if(l==r)return;
		int mid=l+r>>1;
		solve(Ls,l,mid);solve(Rs,mid+1,r);
	}
}T;

int main(){
	scanf("%d%d%d",&n,&m,&q);
	memset(oph,-1,sizeof(oph));
	memset(opv,-1,sizeof(opv));
	F(i,1,m)scanf("%d%d",&p[i].x,&p[i].y),p[i].num=i,lst[i]=1;
	F(i,1,q){
		int op,ti,x,y;
		scanf("%d",&op);
		if(op==1)vis[i]=1,scanf("%d",&x),T.insert(1,1,q,lst[x],i,i),val[i]=p[x],val[i].num=i;
		if(op==2)scanf("%d",&x),oph[i]=x;
		if(op==3)scanf("%d",&x),opv[i]=x;
		if(op==4)scanf("%d%d",&x,&y),m++,p[m]=(point){x,y,m},lst[m]=i;
	}
	T.solve(1,1,q);
	F(i,1,q)if(vis[i]==1)printf("%d %d\n",val[i].x,val[i].y);
	return 0;
}
posted @   冰雾  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示