首页 > 代码库 > bzoj3082: Graph2 离线+线段树
bzoj3082: Graph2 离线+线段树
经典问题。强制在线的话非常复杂。
考虑离线。
每条边的存在时间是一个区间,因此按时间建立一颗线段树,将每条边插入,拆成log条边。然后dfs线段树,每次并查集合并当前节点的所有边,到叶子节点时回答询问,回溯时撤销并查集的修改。
带撤销的并查集不能路径压缩,要按秩合并。
#include<bits/stdc++.h>#define N 200005#define M (l+r>>1)#define P (k<<1)#define S (k<<1|1)#define L l,M,P#define R M+1,r,S#define Z int l=1,int r=q,int k=1#define u first#define v secondusing namespace std;struct io_t{ operator int(){ int x; scanf("%d",&x); return x; }}it;int n=it,m=it,s[N],t[N];int p[N],u[N],v[N],j,q;char d[N];typedef pair<int,int> vec;vec f[N],e[N];vector<vec> a[1<<18];int find(int i){ return p[i]==i ?i:find(p[i]);}void add(vec v,int s,int t,Z){ if(s<=l&&r<=t) a[k].push_back(v); else{ if(s<=M) add(v,s,t,L); if(t>M) add(v,s,t,R); }}void dfs(Z){ for(int j=0;j!=a[k].size();++j){ vec* i=&a[k][j]; i->u=find(i->u); i->v=find(i->v); if(i->u^i->v){ if(u[i->u]<u[i->v]) swap(i->u,i->v); p[i->v]=i->u; u[i->u]+=u[i->v]; } } if(l==r) d[l]^81?0:v[l] =find(f[l].u) ^find(f[l].v); else{ dfs(L);dfs(R); } for(int j=a[k].size()-1;~j;--j){ vec* i=&a[k][j]; if(i->u^i->v){ p[i->v]=i->v; u[i->u]-=u[i->v]; } }}int main(){ for(int i=1;i<=n;++i) u[p[i]=i]=1; for(int i=1;i<=m;++i) e[i]=vec(it,it); q=it; for(int i=1;i<=q;++i){ scanf(" %c%d",d+i,&j); if(d[i]==68) t[j]?0:t[j]=i; if(d[i]==81) f[i]=vec(j,it); if(d[i]==73&&++m){ s[m]=i; e[m]=vec(j,it); } } for(int i=1;i<=m;++i) add(e[i], s[i],t[i]?t[i]:q); dfs(); for(int i=1;i<=q;++i) if(d[i]==81) puts(v[i]?"No":"Yes");}
bzoj3082: Graph2 离线+线段树
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。