【线段树分治】(luoguP5787

洛谷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 }
View Code

猜你喜欢

转载自www.cnblogs.com/xiaobuxie/p/12627651.html