War
考虑把这个问题转化为线段树区间加+区间询问最小值。如果最小值为
把原来的线段树重复利用一下。这样就变成了一个 区间加+区间覆盖+区间最小值线段树。
我们注意到一个性质:对于每组
然后我们发现这个东西其实是一个树形结构,所以我们在每次操作和询问的时候只要在根节点打标记与询问就可以了。
暴力找根是
然后接下来会有一个部分分的想法:对于每个船我完全可以直接大力并查集维护它们是不是在同一个连通块内。因为
然后,我们发现找根完全可以优化成
对于区间重复的情况,我可以直接跳过这个重复的区间,直接跳到不重复的区间里。这个东西可以推一个数学式子表示我要往前跳多少。然后由于这棵树深度最多只有
但是这样因为询问
所以,我们可以把操作全部离线下来,然后把每个相同根节点的操作按顺序排序往下做,当这个根节点的所有操作做完之后,重复利用这个线段树即可。
这题其实暑假就出完了,只能说 Daily OI 挺能鸽的,隔壁出题组一周四个题直接交审核了。
#include<bits/stdc++.h>
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int maxn=5e5+5;
int n,m,s,q,tot,x[maxn],y[maxn],cs,l1[maxn],op[maxn],k[maxn],ans[maxn];
struct edge{int l1,r1,l2,r2;}a[maxn];
struct node{int L,R,p,op,id;}Q[maxn];
struct tree{
int t[maxn*4],lz[maxn*4],lz2[maxn*4];
void pu(int rt)<%t[rt]=min(t[ls],t[rs]);%>
void pd(int rt){
if(lz2[rt])
t[ls]=t[rs]=lz[ls]=lz[rs]=0,
lz2[ls]=lz2[rs]=1,lz2[rt]=0;
if(lz[rt]!=0)
t[ls]+=lz[rt],t[rs]+=lz[rt],
lz[ls]+=lz[rt],lz[rs]+=lz[rt],
lz[rt]=0;
}
void modify1(int rt,int l,int r,int ql,int qr,int p){
if(ql<=l&&r<=qr)<%t[rt]+=p,lz[rt]+=p;return ;%>
pd(rt);
int mid=l+r>>1;
if(ql<=mid)modify1(ls,l,mid,ql,qr,p);
if(qr>mid)modify1(rs,mid+1,r,ql,qr,p);
pu(rt);
}
void modify2(int rt,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)<%t[rt]=0,lz[rt]=0,lz2[rt]=1;return ;%>
pd(rt);
int mid=l+r>>1;
if(ql<=mid)modify2(ls,l,mid,ql,qr);
if(qr>mid)modify2(rs,mid+1,r,ql,qr);
pu(rt);
}
int query(int rt,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return t[rt];
pd(rt);
int mid=l+r>>1,res=1e9;
if(ql<=mid)res=query(ls,l,mid,ql,qr);
if(qr>mid)res=min(res,query(rs,mid+1,r,ql,qr));
return res;
}
}vis;
bool cmp1(node x,node y){
return x.p==y.p?x.id<y.id:x.p<y.p;
}
bool cmp2(edge x,edge y){
return x.l2<y.l2;
}
int jump(int x){
for(int i=s;i>=1;i--)
if(a[i].l2<=x&&a[i].r2>=x){
if(a[i].l2-a[i].l1>=a[i].r2-a[i].l2+1)x=a[i].l1+(x-a[i].l2);
else x-=(x-a[i].l2)/(a[i].l2-a[i].l1)*(a[i].l2-a[i].l1);
if(x>=a[i].l2)x-=(a[i].l2-a[i].l1);
}
else if(a[i].l2<x)return x;
return x;
}
int main(){
scanf("%d%d%d%d",&n,&m,&s,&q);
for(int i=1;i<=s;i++)
scanf("%d%d%d%d",&a[i].l1,&a[i].r1,&a[i].l2,&a[i].r2);
sort(a+1,a+s+1,cmp2);
for(int i=1;i<=q;i++){
Q[i].id=i;
scanf("%d%d",&Q[i].op,&Q[i].p);
if(Q[i].op==1)
scanf("%d%d",&Q[i].L,&Q[i].R),
Q[i].p=jump(Q[i].p);
if(Q[i].op==2)
Q[i]=Q[Q[i].p],Q[i].id=i,Q[i].op=2;
if(Q[i].op==3)
scanf("%d%d",&Q[i].L,&Q[i].R),
Q[i].p=jump(Q[i].p);
}
sort(Q+1,Q+q+1,cmp1);
for(int i=1;i<=q;i++){
if(Q[i].p!=Q[i-1].p)vis.modify2(1,1,m,1,m);
if(Q[i].op==1)vis.modify1(1,1,m,Q[i].L,Q[i].R,1);
if(Q[i].op==2)vis.modify1(1,1,m,Q[i].L,Q[i].R,-1);
if(Q[i].op==3)ans[Q[i].id]=(vis.query(1,1,m,Q[i].L,Q[i].R)>0?2:1);
}
for(int i=1;i<=q;i++)
if(ans[i])printf(ans[i]==2?"Yes\n":"No\n");
return 0;
}
/*
10 20 2 9
1 5 2 6
7 9 8 10
1 4 1 5
3 6 2 3
2 1
3 6 2 3
1 10 2 7
1 9 3 6
2 6
1 7 8 13
3 8 2 12
*/