洛谷P5787:https://www.luogu.com.cn/problem/P5787
题意:某条边 u v 会 在 l , r 时间段内存在,问每个时间点的图是不是二分图。
按照时间轴建树,首先对于修改操作,一个修改操作在线段树上操作会修改 logn 个节点的vector,最后再dfs遍历一整遍处理出询问。
关于判断二分图,其实并查集维护,判断是否有奇环即可。 dis[ u ] 记录 u 到 并查集 直接 父亲 的距离奇偶,然后并查集启发式合并,修改的只有fu的 父亲, fu 的 dis( 变成 dis[u] ^ dis[v] ^ 1), 以及 fv 的siz,Dis(u) 函数计算u到祖父亲的距离奇偶,计算的时候一直往上跑就好了。然后关于正确性:假如说u v 不在一个集合,那么把 fu 和 fv 并起来(也就是上文所说的操作),可以观察到计算Dis 值的时候是正确的。
假如说 u v 不在一个集合 , 那么u、v现在的并查集树绝对是树而没有环,假如 u v 之间有 一条非树边,构成的环一定是偶环,如果是奇环前面就会判断掉,那么u 不经过 非树边 和经过非树边到达 祖父亲的距离奇偶一定是一样的,所以不用保存非树边,也就是现在并查集是树。同样道理,u v 连非树边,假如与树边构成偶环,什么东西也不用变。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 3e5+9; 4 int cnt = 0; 5 vector< pair<int,int> > tr[N*4]; 6 pair<int,int > sta[N]; 7 int f[N],dis[N],siz[N],ans[N]; 8 int find(int x){ if(x == f[x]) return x; return find(f[x]);}; 9 int Dis(int x){ 10 int res = 0; 11 while(x != f[x]){ 12 res ^= dis[x]; 13 x = f[x]; 14 } 15 return res; 16 } 17 void merge(int u,int v){ 18 int fu = find(u) , fv = find(v); 19 if(siz[fu] > siz[fv]){ 20 swap(u,v); 21 swap(fu,fv); 22 } 23 f[ fu ] = fv; 24 dis[fu] = ( dis[u] ^ dis[v] ^ 1 ); 25 siz[fv] += siz[fu]; 26 sta[++cnt] = make_pair(fu,fv); 27 } 28 void add(int o,int l,int r,int x,int y,pair<int,int> w){ 29 if( x<= l && r <= y){ 30 tr[o].push_back(w); 31 return; 32 } 33 int m = (l+r)>>1; 34 if(x<=m) add(o<<1,l,m,x,y,w); 35 if( y > m) add(o<<1|1,m+1,r,x,y,w); 36 return; 37 } 38 void dfs(int o,int l,int r){ 39 int k = cnt; 40 bool ok = 1; 41 for(auto w : tr[o] ){ 42 int u = w.first,v = w.second; 43 int fu = find(u) , fv = find(v); 44 if( fu == fv ){ 45 if( (Dis(u) ^ Dis(v) ) == 0 ){ 46 ok = 0; 47 for(int i = l;i<=r;++i) ans[i] = 0; 48 break; 49 } 50 } 51 else merge(u,v); 52 } 53 if(ok){ 54 if(l==r) ans[l] = 1; 55 else{ 56 int m = (l+r)>>1; 57 dfs(o<<1,l,m); 58 dfs(o<<1|1,m+1,r); 59 } 60 } 61 while(cnt != k){ 62 int u = sta[cnt].first , v = sta[cnt].second; 63 f[u] = u; 64 dis[u] = 0; 65 siz[v] -= siz[u]; 66 --cnt; 67 } 68 } 69 int main(){ 70 int n,m,k; 71 scanf("%d %d %d",&n,&m,&k); 72 for(int i = 1;i<=m;++i){ 73 int u,v,l,r; scanf("%d %d %d %d",&u,&v,&l,&r); 74 if( l < r ) add(1,1,k,l+1,r,make_pair(u,v)); 75 } 76 for(int i = 1;i<=n;++i) f[i] = i , siz[i] = 1,dis[i] = 0; 77 dfs(1,1,k); 78 for(int i = 1;i<=n;++i){ 79 if(ans[i]) puts("Yes"); 80 else puts("No"); 81 } 82 return 0; 83 }