视频链接:
P2147 [SDOI2008] 洞穴勘测 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
// 线段树分治 O(mlogmlogm) #include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <map> using namespace std; #define ls (u<<1) #define rs (u<<1|1) #define mid ((l+r)>>1) const int N=200005; int n,m,top,ans[N]; int p[N],siz[N]; //并查集 struct node{ int x,y; }st[N]; //栈 struct Q{ int x,y,b; //b=1是查询,b=0不是 bool operator<(const Q &a)const{ return x==a.x?y<a.y:x<a.x; } }q[N]; //操作 vector<Q>tr[N<<2]; //节点 map<Q,int> mp; //操作信息<<x,y,b>,i> void insert(int u,int l,int r,int L,int R,Q q){ if(l>R||r<L) return; if(L<=l&&r<=R) return tr[u].push_back(q); insert(ls,l,mid,L,R,q); insert(rs,mid+1,r,L,R,q); } int find(int x){ //查找根 return p[x]==x?x:find(p[x]); } void merge(int x,int y){ //合并集合 x=find(x),y=find(y); if(x==y) return; if(siz[x]>siz[y]) swap(x,y); st[++top]={x,y}; p[x]=y; siz[y]+=siz[x]; } void solve(int u,int l,int r){ int now=top; for(auto i:tr[u]) merge(i.x,i.y); if(l==r){ if(q[l].b) ans[l]=find(q[l].x)==find(q[l].y); } else solve(ls,l,mid),solve(rs,mid+1,r); while(top>now){ //撤销合并 node t=st[top--]; p[t.x]=t.x; siz[t.y]-=siz[t.x]; } } int main(){ scanf("%d%d",&n,&m); char op[9]; for(int i=1;i<=n;i++) p[i]=i,siz[i]=1; for(int i=1,x,y;i<=m;i++){ scanf("%s%d%d",op,&x,&y); if(x>y) swap(x,y); //保证映射唯一 if(op[0]=='C'){ q[i]={x,y,0}; mp[q[i]]=i; //记录边q[i]的出现时刻 } else if(op[0]=='D'){ q[i]={x,y,0}; insert(1,1,m,mp[q[i]],i,q[i]);//插入q[i]的出现时间 mp.erase(q[i]); //删除边q[i] } else q[i]={x,y,1}; //q[i]是查询 } for(auto i:mp) //插入每条边的出现时间 insert(1,1,m,i.second,m,i.first); solve(1,1,m); for(int i=1;i<=m;i++)if(q[i].b)puts(ans[i]?"Yes":"No"); }
标签:P2147,C137,include,int,siz,top,solve,mp,SDOI2008 From: https://www.cnblogs.com/dx123/p/18239902