BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)
题目大意:略
涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上
用$LCT$维护一个树上集合就好
因为它维护了树上集合,所以它别的啥都干不了了
发现树是静态的,可以用$dfs$序搞搞
把问题当成树上节点涂色会很麻烦
但只有相邻的不同颜色节点才会对答案产生影响
所以我们把涂色当成一种连边/断边操作
这样,问题就容易解决得多了
维护一个数组$f_{x}$表示$x$节点到根的路径上一共有$f_{x}$种颜色,$f_{x}-1$条断边
显然它的初始值就是节点x的深度
第一个操作,把这个位置到根打通
每断一条边,子树每个节点答案$+1$,连一条边,答案$-1$
在$access$操作中进行讨论即可
第二个操作,求链上不同颜色数量,即一个链的断边数量$-1$
显然,答案是$(f_{x}-1)+(f_{y}-1)-2*(f_{lca(x,y)}-1)+1=f_{x}+f_{y}-2*f_{lca(x,y)}+1$
即断边总数$+1$
不要把它当成节点的颜色去想
第三个操作,求子树内$f_{x}$最大值
以上操作皆可用$dfs$序+线段树实现!
随时保持清醒头脑,千万不要把这个$LCT$当成真正的$LCT$,它只是一个维护链集合的媒介!
尤其是断边/连边,进行区间修改操作时,需要找出开头/后继节点,而不是当前splay的根节点
1 #include <queue> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #define N1 101000 7 #define S1 (N1<<1) 8 #define T1 (N1<<2) 9 #define ll long long 10 #define uint unsigned int 11 #define rint register int 12 #define ull unsigned long long 13 #define dd double 14 #define il inline 15 #define inf 1000000000 16 using namespace std; 17 18 int gint() 19 { 20 int ret=0,fh=1;char c=getchar(); 21 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 22 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 23 return ret*fh; 24 } 25 int n,m,T; 26 struct Edge{ 27 int to[N1*2],nxt[N1*2],head[N1],cte; 28 void ae(int u,int v) 29 {cte++;to[cte]=v,nxt[cte]=head[u],head[u]=cte;} 30 }E; 31 32 struct SEG{ 33 int ma[N1<<2],tag[N1<<2]; 34 void pushup(int rt){ma[rt]=max(ma[rt<<1],ma[rt<<1|1]);} 35 void pushdown(int rt) 36 { 37 if(!tag[rt]) return; 38 ma[rt<<1]+=tag[rt]; ma[rt<<1|1]+=tag[rt]; 39 tag[rt<<1]+=tag[rt]; tag[rt<<1|1]+=tag[rt]; 40 tag[rt]=0; 41 } 42 void build(int *a,int *id,int l,int r,int rt) 43 { 44 if(l==r) {ma[rt]=a[id[l]];return;} 45 int mid=(l+r)>>1; 46 build(a,id,l,mid,rt<<1); 47 build(a,id,mid+1,r,rt<<1|1); 48 pushup(rt); 49 } 50 void update(int L,int R,int l,int r,int rt,int w) 51 { 52 if(!L||!R||L>R) return; 53 if(L<=l&&r<=R) {ma[rt]+=w,tag[rt]+=w;return;} 54 int mid=(l+r)>>1; pushdown(rt); 55 if(L<=mid) update(L,R,l,mid,rt<<1,w); 56 if(R>mid) update(L,R,mid+1,r,rt<<1|1,w); 57 pushup(rt); 58 } 59 int query(int L,int R,int l,int r,int rt) 60 { 61 if(L<=l&&r<=R) return ma[rt]; 62 int mid=(l+r)>>1,ans=0; pushdown(rt); 63 if(L<=mid) ans=max(ans,query(L,R,l,mid,rt<<1)); 64 if(R>mid) ans=max(ans,query(L,R,mid+1,r,rt<<1|1)); 65 return ans; 66 } 67 }s; 68 69 namespace lct{ 70 int ch[N1][2],fa[N1]; 71 int idf(int x){return ch[fa[x]][0]==x?0:1;} 72 int isroot(int x){return (ch[fa[x]][0]==x||ch[fa[x]][1]==x)?0:1;} 73 //int stk[N1],tp; 74 void rot(int x) 75 { 76 int y=fa[x],ff=fa[y],px=idf(x),py=idf(y); 77 if(!isroot(y)) ch[ff][py]=x; fa[x]=ff; 78 fa[ch[x][px^1]]=y,ch[y][px]=ch[x][px^1]; 79 ch[x][px^1]=y,fa[y]=x; 80 //pushup(y),pushup(x); 81 } 82 void splay(int x) 83 { 84 int y=x; /*stk[++tp]=x; 85 while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];} 86 while(tp){pushdown(stk[tp--]);}*/ 87 while(!isroot(x)) 88 { 89 y=fa[x]; 90 if(isroot(y)) rot(x); 91 else if(idf(y)==idf(x)) rot(y),rot(x); 92 else rot(x),rot(x); 93 } 94 } 95 int First(int x){while(ch[x][0]) x=ch[x][0];return x;} 96 int upper(int x){x=ch[x][1];while(ch[x][0]) x=ch[x][0];return x;} 97 void access(int x,int *st,int *ed) 98 { 99 for(int y=0,z;x;) 100 { 101 splay(x); 102 z=upper(x); 103 if(z) s.update(st[z],ed[z],1,n,1,1); 104 z=First(y); 105 s.update(st[z],ed[z],1,n,1,-1); 106 ch[x][1]=y; y=x; x=fa[x]; 107 } 108 } 109 void init(int *ff){ 110 for(int i=2;i<=n;i++) fa[i]=ff[i]; 111 } 112 }; 113 114 int fa[N1],son[N1],sz[N1],tp[N1],dep[N1]; 115 int st[N1],ed[N1],id[N1],tot; 116 void dfs1(int u,int ff) 117 { 118 for(int j=E.head[u];j;j=E.nxt[j]) 119 { 120 int v=E.to[j]; 121 if(v==ff) continue; 122 dep[v]=dep[u]+1; dfs1(v,u); fa[v]=u; 123 sz[u]+=sz[v]; son[u]=sz[v]>sz[son[u]]?v:son[u]; 124 } 125 sz[u]++; 126 } 127 void dfs2(int u) 128 { 129 st[u]=ed[u]=++tot; id[tot]=u; 130 if(son[u]) tp[son[u]]=tp[u], dfs2(son[u]), ed[u]=max(ed[u],ed[son[u]]);; 131 for(int j=E.head[u];j;j=E.nxt[j]) 132 { 133 int v=E.to[j]; 134 if(v==fa[u]||v==son[u]) continue; 135 tp[v]=v; dfs2(v); 136 ed[u]=max(ed[u],ed[v]); 137 } 138 } 139 int lca(int x,int y) 140 { 141 while(tp[x]!=tp[y]) 142 { 143 if(dep[tp[x]]<dep[tp[y]]) swap(x,y); 144 x=fa[tp[x]]; 145 } 146 return dep[x]<dep[y]?x:y; 147 } 148 void mksame(int x) 149 { 150 lct::access(x,st,ed); 151 } 152 int split(int x,int y) 153 { 154 int sx,sy,sf,f=lca(x,y); 155 sx=s.query(st[x],st[x],1,n,1); 156 sy=s.query(st[y],st[y],1,n,1); 157 sf=s.query(st[f],st[f],1,n,1); 158 return sx+sy-2*sf+1; 159 } 160 int qmax(int x){return s.query(st[x],ed[x],1,n,1);} 161 void init() 162 { 163 dep[1]=1; dfs1(1,-1); 164 tp[1]=1; dfs2(1); 165 lct::init(fa); 166 s.build(dep,id,1,n,1); 167 } 168 169 int qf(int x){return s.query(st[x],st[x],1,n,1);} 170 171 int main() 172 { 173 scanf("%d%d",&n,&m); 174 int i,j,fl,x,y,cnt=0,de; 175 for(i=1;i<n;i++) x=gint(), y=gint(), E.ae(x,y), E.ae(y,x); 176 init(); 177 for(j=1;j<=m;j++) 178 { 179 fl=gint(); 180 if(fl==1){ 181 x=gint(); 182 mksame(x); 183 }else if(fl==2){ 184 x=gint(); y=gint(); 185 printf("%d\n",split(x,y)); 186 }else{ 187 x=gint(); 188 printf("%d\n",qmax(x)); 189 } 190 } 191 return 0; 192 }