CF1578B 题解
CF 官方题解做法。
不难发现一个连通块内部的连边情况不重要,我们可以将其视为一个多边形,即每个点连向下一个同连通块内的点。
断环成链,形成如下结构:
由于任意两个连通块不会相交,我们令
来看连边操作。设连接
重复上述过程,直至
注意到相邻点的
合并又分两种情况。用
于是此题得解。复杂度
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
int n,m;
struct dsu {
int fa[N],l[N],r[N];
void init() {for(int i=1;i<=n;i++) fa[i]=l[i]=r[i]=i;}
int get(int x) {return fa[x]==x?x:fa[x]=get(fa[x]);}
void merge(int x,int y) {
x=get(x); y=get(y);
if(x==y) return ;
fa[x]=y; l[y]=min(l[x],l[y]); r[y]=max(r[x],r[y]);
}
} s;
struct sgt {
int mn[4*N],add[4*N];
void pushval(int p,int v) {mn[p]+=v; add[p]+=v;}
void pushdown(int p) {
if(!add[p]) return ;
pushval(p<<1,add[p]); pushval(p<<1|1,add[p]);
add[p]=0;
}
void modify(int L,int R,int v,int p=1,int l=1,int r=n) {
if(L>R) return ;
if(L<=l&&r<=R) {pushval(p,v); return ;}
int mid=l+r>>1; pushdown(p);
if(L<=mid) modify(L,R,v,p<<1,l,mid);
if(R>mid) modify(L,R,v,p<<1|1,mid+1,r);
mn[p]=min(mn[p<<1],mn[p<<1|1]);
}
int query(int x,int p=1,int l=1,int r=n) {
if(l==r) return mn[p];
int mid=l+r>>1; pushdown(p);
if(x<=mid) return query(x,p<<1,l,mid);
return query(x,p<<1|1,mid+1,r);
}
int binaryl(int x,int v,int p=1,int l=1,int r=n) {
if(r<=x) {
if(mn[p]>=v) return 0;
if(l==r) return l;
int mid=l+r>>1; pushdown(p);
if(mn[p<<1|1]<v) return binaryl(x,v,p<<1|1,mid+1,r);
return binaryl(x,v,p<<1,l,mid);
}
int mid=l+r>>1,res=0; pushdown(p);
if(mid+1<=x) res=binaryl(x,v,p<<1|1,mid+1,r);
if(!res) res=binaryl(x,v,p<<1,l,mid);
return res;
}
int binaryr(int x,int v,int p=1,int l=1,int r=n) {
if(x<=l) {
if(mn[p]>=v) return n+1;
if(l==r) return l;
int mid=l+r>>1; pushdown(p);
if(mn[p<<1]<v) return binaryr(x,v,p<<1,l,mid);
return binaryr(x,v,p<<1|1,mid+1,r);
}
int mid=l+r>>1,res=n+1; pushdown(p);
if(x<=mid) res=binaryr(x,v,p<<1,l,mid);
if(res==n+1) res=binaryr(x,v,p<<1|1,mid+1,r);
return res;
}
} t;
void merge(int x,int y) {
x=s.get(x); y=s.get(y);
if(s.r[x]<s.l[y]) t.modify(s.r[x]+1,s.l[y]-1,1);
else t.modify(max(s.l[x],s.l[y]),min(s.r[x],s.r[y]),-1);
s.merge(x,y);
}
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n>>m;
s.init();
while(m--) {
int op,x,y;
cin>>op>>x>>y;
if(op==1) {
if(x>y) swap(x,y);
int vx=t.query(x),vy=t.query(y);
while(s.get(x)!=s.get(y)) {
if(vx>vy) {merge(x,t.binaryr(x,vx)); vx--;}
else if(vx<vy) {merge(t.binaryl(y,vy),y); vy--;}
else {
int p=t.binaryr(x,vx);
if(p<y) {merge(x,p); vx--;}
else merge(x,y);
}
}
}
else cout<<(s.get(x)==s.get(y));
}
return 0;
}