首页 > 代码库 > bzoj4817 [Sdoi2017]树点涂色

bzoj4817 [Sdoi2017]树点涂色

传送门

吐槽一波怎么今年的山东OI这么水……(B

不难看出第一种操作就是LCT的access,那么每个点到根节点的颜色种数就是虚边数量+1,两点间颜色种数同理……

第三种操作可以用把每个虚边挂着的点的子树权值全部+1的方式来维护,那么直接LCT+区间修改区间求max的线段树维护即可,复杂度$O(n\log^2 n)$。

技术分享
  1 /**************************************************************
  2     Problem: 4817
  3     User: _Angel_
  4     Language: C++
  5     Result: Accepted
  6     Time:5500 ms
  7     Memory:21092 kb
  8 ****************************************************************/
  9 #include<cstdio>
 10 #include<cstring>
 11 #include<algorithm>
 12 #include<vector>
 13 #define isroot(x) ((x)->p==null||((x)!=(x)->p->ch[0]&&(x)!=(x)->p->ch[1]))
 14 #define dir(x) ((x)==(x)->p->ch[1])
 15 using namespace std;
 16 const int maxn=100010;
 17 struct node{node *ch[2],*p;}null[maxn];
 18 void dfs(int);
 19 int LCA(int,int);
 20 node *access(node*);
 21 node *getroot(node*);
 22 void splay(node*);
 23 void rot(node*,int);
 24 void modify(int,int,int);
 25 int query(int,int,int);
 26 int mx[maxn<<2]={0},lazy[maxn<<2]={0};
 27 vector<int>G[maxn];
 28 int f[maxn][20],d[maxn],dfn[maxn],finish[maxn],tim=0;
 29 int n,m,lgn=0,s,t,k,x,y;
 30 int main(){
 31     null->ch[0]=null->ch[1]=null->p=null;
 32     scanf("%d%d",&n,&m);
 33     for(int i=1;i<=n;i++)null[i].ch[0]=null[i].ch[1]=null[i].p=null;
 34     for(int i=1;i<n;i++){
 35         scanf("%d%d",&x,&y);
 36         G[x].push_back(y);
 37         G[y].push_back(x);
 38     }
 39     dfs(1);
 40     for(int j=1;j<=lgn;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
 41     while(m--){
 42         scanf("%d%d",&k,&x);
 43         if(k==1)access(null+x);
 44         else if(k==2){
 45             scanf("%d",&y);
 46             s=t=dfn[x];
 47             int ans=query(1,n,1);
 48             s=t=dfn[y];
 49             ans+=query(1,n,1);
 50             s=t=dfn[LCA(x,y)];
 51             ans-=query(1,n,1)<<1;
 52             printf("%d\n",ans+1);
 53         }
 54         else if(k==3){
 55             s=dfn[x];
 56             t=finish[x];
 57             printf("%d\n",query(1,n,1)+1);
 58         }
 59     }
 60     return 0;
 61 }
 62 void dfs(int x){
 63     dfn[x]=++tim;
 64     d[x]=d[f[x][0]]+1;
 65     null[x].p=null+f[x][0];
 66     while((1<<lgn)<d[x])lgn++;
 67     for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=f[x][0]){
 68         f[G[x][i]][0]=x;
 69         dfs(G[x][i]);
 70     }
 71     finish[x]=tim;
 72     if(f[x][0]){
 73         s=dfn[x];
 74         t=finish[x];
 75         k=1;
 76         modify(1,n,1);
 77     }
 78 }
 79 int LCA(int x,int y){
 80     if(d[x]!=d[y]){
 81         if(d[x]<d[y])swap(x,y);
 82         for(int i=lgn;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
 83     }
 84     if(x==y)return x;
 85     for(int i=lgn;i>=0;i--)if(f[x][i]!=f[y][i]){
 86         x=f[x][i];
 87         y=f[y][i];
 88     }
 89     return f[x][0];
 90 }
 91 node *access(node *x){
 92     node *y=null;
 93     while(x!=null){
 94         splay(x);
 95         if(x->ch[1]!=null){
 96             node *u=x->ch[1];
 97             x->ch[1]=null;
 98             u=getroot(u);
 99             s=dfn[u-null];
100             t=finish[u-null];
101             k=1;
102             modify(1,n,1);
103         }
104         if(y!=null){
105             y=getroot(y);
106             s=dfn[y-null];
107             t=finish[y-null];
108             k=-1;
109             modify(1,n,1);
110         }
111         x->ch[1]=y;
112         y=x;
113         x=x->p;
114     }
115     return y;
116 }
117 node *getroot(node *x){
118     splay(x);
119     while(x->ch[0]!=null)x=x->ch[0];
120     splay(x);
121     return x;
122 }
123 void splay(node *x){
124     while(!isroot(x)){
125         if(isroot(x->p)){
126             rot(x->p,dir(x)^1);
127             break;
128         }
129         if(dir(x)==dir(x->p))rot(x->p->p,dir(x->p)^1);
130         else rot(x->p,dir(x)^1);
131         rot(x->p,dir(x)^1);
132     }
133 }
134 inline void rot(node *x,int d){
135     node *y=x->ch[d^1];
136     if((x->ch[d^1]=y->ch[d])!=null)y->ch[d]->p=x;
137     y->p=x->p;
138     if(!isroot(x))x->p->ch[dir(x)]=y;
139     (y->ch[d]=x)->p=y;
140 }
141 void modify(int l,int r,int rt){
142     if(s<=l&&t>=r){
143         mx[rt]+=k;
144         lazy[rt]+=k;
145         return;
146     }
147     int mid=(l+r)>>1;
148     if(s<=mid)modify(l,mid,rt<<1);
149     if(t>mid)modify(mid+1,r,rt<<1|1);
150     mx[rt]=max(mx[rt<<1],mx[rt<<1|1])+lazy[rt];
151 }
152 int query(int l,int r,int rt){
153     if(s<=l&&t>=r)return mx[rt];
154     int mid=(l+r)>>1,ans=0;
155     if(s<=mid)ans=max(ans,query(l,mid,rt<<1));
156     if(t>mid)ans=max(ans,query(mid+1,r,rt<<1|1));
157     return ans+lazy[rt];
158 }
View Code

ps:如果没记错的话,这题应该是重组病毒那题的超级弱化版……

bzoj4817 [Sdoi2017]树点涂色