【JOISC2020】扫除
【JOISC2020】扫除
Description
由于 Bitaro AK 了 IOI,所以 IOI 主办方送了他一套房子,为一个边长为 的等腰直角三角形。房间内一点用坐标 表示,其中 。直角顶点为原点,三角形两腰分别为 轴与 轴。
一天,Bitaro 发现自己已经 AK 了 1919810 届 IOI 闲的没事做准备打扫房间里的灰尘。这些灰尘一开始一共有 堆,其中第 堆位于 。同时,可能存在多堆灰尘位于同一个位置上的情况。
现在 Bitaro 准备用扫帚打扫房间。我们认为扫帚是放置在房间里的一条线段,并且将这条线段的长度称为扫帚的宽度。由于 Bitaro 很有条理,所以他只会用以下的两种方式打扫房间:
-
Bitaro 将扫帚平行于 轴放置,一端位于原点。然后他会水平向上移动扫帚,直到不能移动为止。如果扫帚的宽度为 ,那么原来一堆满足 的灰尘 将会被移动到 。(这个位置可能会存在多堆灰尘)我们称这个过程为过程 H。
-
Bitaro 将扫帚平行于 轴放置,一端位于原点。然后他会垂直向右移动扫帚,直到不能移动为止。如果扫帚的宽度为 ,那么原来一堆满足 的灰尘 将会被移动到 。(这个位置可能会存在多堆灰尘)我们称这个过程为过程 V。
在 Bitaro 的房间里,依次会发生 个事件。第 个事件形如以下 种:
-
Bitaro 想要计算第 堆灰尘的位置坐标;
-
Bitaro 使用宽度为 的扫帚,进行了过程 H;
-
Bitaro 使用宽度为 的扫帚,进行了过程 V;
-
有一堆新的灰尘出现在点 处。如果在这个事件之前一共有 堆灰尘,那么这堆灰尘就是房间中的第 堆灰尘。
由于 Bitaro 已经 AK 了 IOI,啥都不想干,所以你需要写一个程序,给出房间的腰长,每一堆灰尘的位置坐标和每个事件的细节,求出要求的某堆灰尘的位置坐标。
Input
第一行三个整数,分别为 。
接下来 行,每行两个整数 ,表示第 堆灰尘一开始的位置。
接下来 行,每行两到三个整数,表示一个事件。设 为第一个整数,每行含义如下:
-
如果 ,则这行有两个整数 ,表示 Bitaro 要计算第 堆灰尘的坐标;
-
如果 ,则这行有两个整数 ,表示 Bitaro 用宽度为 的扫帚进行了过程 H;
-
如果 ,则这行有两个整数 ,表示 Bitaro 用宽度为 的扫帚进行了过程 V;
-
如果 ,则这行有三个整数 ,表示一堆新的灰尘出现在 位置。
Output
对于每个 的事件,输出一行两个整数,表示事件 发生时第 堆灰尘的位置坐标。
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
对于 的数据,。保证:
-
;
-
,其中 表示事件 发生时灰尘的堆数;
-
;
-
;
-
至少存在一个 的事件。
Solution
可以从最简单的情况入手
假设只有一种修改,所有询问在修改后,同时没有插入点
显然只要在线段树上改一改扫一扫就行了
现在考虑有两种修改
可以发现的是 V 和 H 可以互相影响,但 V 操作内部独立,H 操作同理
然后考虑求出每个操作所影响的最小坐标
显然一个 V 会让内的 H 上
可以线段树维护
最后考虑插入
很容易可以求出一个询问所用的修改区间
所以直接线段树分治就行了
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通