[cf576E]Painting Edges

先线段树分治,但事实上与普通的动态连通性/二分图的判定有很大的区别:

1.对每一个修改(建议将初始的边也作为无色修改),在其第一次修改时进行判定,若发现不合法则将其颜色改为对该边最后一次可行的修改,之后再执行即可;

2.操作顺序会影响,有可能左子树中的操作先于父亲的操作

对于此类操作,必然要求父亲之前未被操作(否则没有影响),换言之其左端点恰好为区间左端点

注意到由于左端点各不相同,因此比其早的操作一定恰好是他的一条左链(左儿子、左儿子的左儿子……)上的所有操作

具体实现可以记录当前那个不确定是否执行的操作(根据左端点各不相同,是唯一的),在搜索到叶子时再判断,当左儿子返回合法后再执行(注意每一个左儿子返回都要执行)

时间复杂度为$o(nlog^{2}n+nk)$($n$、$m$、$q$同阶,两个log分别是线段树分治和并查集,$nk$是初始化并查集),可以通过

(代码有点问题,拍不出来懒得查了,思路yy的感觉没啥问题)

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 500005
  4 #define L (k<<1)
  5 #define R (L+1)
  6 #define mid (l+r>>1)
  7 struct ji{
  8     int id,c;
  9 }u[N<<1];
 10 vector<int>v[N<<3];
 11 int n,m,q,un,x[N],y[N],las[N],ans[N<<1];
 12 void update(int k,int l,int r,int x,int y,int z){
 13     if ((l>y)||(x>r))return;
 14     if ((x<=l)&&(r<=y)){
 15         v[k].push_back(z);
 16         return;
 17     }
 18     update(L,l,mid,x,y,z);
 19     update(R,mid+1,r,x,y,z);
 20 }
 21 struct union_find{
 22     int len[N],d[N],sz[N],f[N];
 23     vector<int>v;
 24     void init(){
 25         for(int i=1;i<=n;i++){
 26             f[i]=i;
 27             sz[i]=1;
 28         }
 29     }
 30     int find(int k){
 31         if (k==f[k]){
 32             d[k]=0;
 33             return k;
 34         }
 35         int fa=find(f[k]);
 36         d[k]=(d[f[k]]^len[k]);
 37         return fa;
 38     }
 39     bool add(int x,int y){//0表示产生奇环 
 40         if (find(x)==find(y))return d[x]^d[y];
 41         int p=(d[x]^d[y]);
 42         x=find(x),y=find(y);
 43         if (sz[x]<sz[y])swap(x,y);
 44         v.push_back(y);
 45         f[y]=x;
 46         len[y]=(p^1);
 47         sz[x]+=sz[y];
 48         return 1;
 49     }
 50     void ctrlz(int now){
 51         while (v.size()>now){
 52             int k=v.back();
 53             v.pop_back();
 54             sz[f[k]]-=sz[k];
 55             len[k]=0;
 56             f[k]=k;
 57         }
 58     }
 59 }T[51];
 60 bool check(int k){
 61     int id=u[k].id;
 62     ans[k]=T[u[k].c].add(x[id],y[id]);
 63     if (!u[k].c)ans[k]=1;
 64     if (!ans[k])u[k].c=las[id];
 65     return ans[k];
 66 }
 67 void add(int k){
 68     int id=u[k].id;
 69     T[u[k].c].add(x[id],y[id]);
 70     las[id]=u[k].c;
 71 }
 72 bool dfs(int k,int l,int r,int un){
 73     int flag=0,now[51];
 74     for(int i=0;i<=50;i++)now[i]=T[i].v.size();
 75     for(int i=0;i<v[k].size();i++)
 76         if (ans[v[k][i]]>=0)add(v[k][i]);
 77         else un=v[k][i];
 78     if (l==r){
 79         if (un)flag=check(un); 
 80     }
 81     else{
 82         flag=dfs(L,l,mid,un);
 83         if (flag)add(un);
 84         dfs(R,mid+1,r,0);
 85     }
 86     for(int i=0;i<=50;i++)T[i].ctrlz(now[i]);
 87     return flag;
 88 }
 89 int main(){
 90     scanf("%d%d%*d%d",&n,&m,&q);
 91     for(int i=1;i<=m;i++){
 92         scanf("%d%d",&x[i],&y[i]);
 93         u[i].id=las[i]=i;
 94     }
 95     for(int i=m+1;i<=q+m;i++){
 96         scanf("%d%d",&u[i].id,&u[i].c);
 97         update(1,1,m+q,las[u[i].id],i-1,las[u[i].id]);
 98         las[u[i].id]=i;
 99     }
100     for(int i=1;i<=m;i++)update(1,1,m+q,las[i],m+q,las[i]);
101     memset(las,0,sizeof(las));
102     memset(ans,-1,sizeof(ans));
103     for(int i=1;i<=m;i++)ans[i]=1;
104     for(int i=0;i<=50;i++)T[i].init();
105     dfs(1,1,m+q,0);
106     for(int i=m+1;i<=m+q;i++)
107         if (ans[i])printf("YES
");
108         else printf("NO
");
109     return 0;
110 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14382888.html