bzoj4817 [Sdoi2017]树点涂色
Description
Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:求x到y的路径的权值。
3 x y:在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作
Input
第一行两个数n,m。
接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
接下来m行,表示操作,格式见题目描述
1<=n,m<=100000
Output
每当出现2,3操作,输出一行。
如果是2操作,输出一个数表示路径的权值
如果是3操作,输出一个数表示权值的最大值
Sample Input
5 6
1 2
2 3
3 4
3 5
2 4 5
3 3
1 4
2 4 5
1 5
2 4 5
1 2
2 3
3 4
3 5
2 4 5
3 3
1 4
2 4 5
1 5
2 4 5
Sample Output
3
4
2
2
4
2
2
正解:$link-cut tree$+树链剖分+线段树。
这道题很巧妙啊。。利用$LCT$的神奇性质完美地解决了询问$1$的棘手操作。
首先我们注意到,询问$1$其实就是$LCT$中的$access$操作。我们可以直接维护每个点到根节点的权值,然后利用$access$操作来处理这个问题。
我们在$access$操作的时候,直接将当前点原来的实儿子所在的子树权值$+1$,当前待接上的实儿子所在子树权值$-1$,就能完美地处理这个操作了。注意,这里指的实儿子一定是在原树中深度最浅的点。我比较偷懒,就直接暴力找$splay$中深度最小的点。具体解释的话,画个图就能理解了,看下代码应该能弄懂吧。。
对于询问$2$,我们可以发现,路径上的权值就是$val[x]+val[y]-2*val[lca(x,y)]+1$。这个式子是很好画图证明的。
首先,$lca$的两个儿子颜色是不可能相同的,所以我们分两种情况讨论一下,一种是$lca$和其中一个儿子颜色相同,一种是$lca$和两个儿子颜色都不同。这样我们就能很容易地得出上述结论。
对于询问$3$,我们直接区间查询,询问子树中的权值最大值就行了。
以上操作,维护权值都是用线段树,求$lca$写树链剖分比较方便。然后我们就能$AC$此题了,虽然复杂度还是很玄学。。
第一次$bzoj \ rank1$。。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define inf (1<<30) 15 #define N (100010) 16 #define ls (x<<1) 17 #define rs (x<<1|1) 18 #define il inline 19 #define RG register 20 #define ll long long 21 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 22 23 using namespace std; 24 25 struct edge{ int nt,to; }g[2*N]; 26 27 int head[N],n,m,num; 28 29 struct tree_cut{ 30 31 int top[N],fa[N],son[N],sz[N],dep[N],pos[N],tid[N],ed[N],cnt; 32 33 il void dfs1(RG int x,RG int p){ 34 fa[x]=p,dep[x]=dep[p]+1,sz[x]=1; RG int v; 35 for (RG int i=head[x];i;i=g[i].nt){ 36 v=g[i].to; if (v==p) continue; 37 dfs1(v,x),sz[x]+=sz[v]; 38 if (sz[son[x]]<=sz[v]) son[x]=v; 39 } 40 return; 41 } 42 43 il void dfs2(RG int x,RG int p,RG int anc){ 44 top[x]=anc,tid[x]=++cnt,pos[cnt]=x; 45 if (son[x]) dfs2(son[x],x,anc); RG int v; 46 for (RG int i=head[x];i;i=g[i].nt){ 47 v=g[i].to; if (v==p || v==son[x]) continue; 48 dfs2(v,x,v); 49 } 50 ed[x]=cnt; return; 51 } 52 53 il int lca(RG int u,RG int v){ 54 while (top[u]!=top[v]){ 55 if (dep[top[u]]<dep[top[v]]) swap(u,v); 56 u=fa[top[u]]; 57 } 58 return dep[u]<dep[v] ? u : v; 59 } 60 61 }tree; 62 63 struct segment_tree{ 64 65 int mx[4*N],lazy[4*N]; 66 67 il void pushdown(RG int x){ 68 mx[ls]+=lazy[x],mx[rs]+=lazy[x]; 69 lazy[ls]+=lazy[x],lazy[rs]+=lazy[x]; 70 lazy[x]=0; return; 71 } 72 73 il void build(RG int x,RG int l,RG int r){ 74 if (l==r){ mx[x]=tree.dep[tree.pos[l]]; return; } 75 RG int mid=(l+r)>>1; 76 build(ls,l,mid),build(rs,mid+1,r); 77 mx[x]=max(mx[ls],mx[rs]); return; 78 } 79 80 il void update(RG int x,RG int l,RG int r,RG int xl,RG int xr,RG int v){ 81 if (xl<=l && r<=xr){ mx[x]+=v,lazy[x]+=v; return; } 82 if (lazy[x]) pushdown(x); RG int mid=(l+r)>>1; 83 if (xr<=mid) update(ls,l,mid,xl,xr,v); 84 else if (xl>mid) update(rs,mid+1,r,xl,xr,v); 85 else update(ls,l,mid,xl,mid,v),update(rs,mid+1,r,mid+1,xr,v); 86 mx[x]=max(mx[ls],mx[rs]); return; 87 } 88 89 il int querymax(RG int x,RG int l,RG int r,RG int xl,RG int xr){ 90 if (xl<=l && r<=xr) return mx[x]; 91 if (lazy[x]) pushdown(x); RG int mid=(l+r)>>1; 92 if (xr<=mid) return querymax(ls,l,mid,xl,xr); 93 else if (xl>mid) return querymax(rs,mid+1,r,xl,xr); 94 else return max(querymax(ls,l,mid,xl,mid),querymax(rs,mid+1,r,mid+1,xr)); 95 } 96 97 il int ask(RG int x){ return querymax(1,1,n,tree.tid[x],tree.tid[x]); } 98 99 }seg; 100 101 struct link_cut_tree{ 102 103 int ch[N][2],fa[N]; 104 105 il int isroot(RG int x){ 106 return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x; 107 } 108 109 il void rotate(RG int x){ 110 RG int y=fa[x],z=fa[y],k=ch[y][0]==x; 111 if (!isroot(y)) ch[z][ch[z][1]==y]=x; 112 fa[x]=z,ch[y][k^1]=ch[x][k],fa[ch[x][k]]=y; 113 ch[x][k]=y,fa[y]=x; return; 114 } 115 116 il void splay(RG int x){ 117 while (!isroot(x)){ 118 RG int y=fa[x],z=fa[y]; 119 if (!isroot(y)){ 120 if ((ch[y][0]==x)^(ch[z][0]==y)) rotate(x); 121 else rotate(y); 122 } 123 rotate(x); 124 } 125 return; 126 } 127 128 il void access(RG int x){ 129 RG int t=0; 130 while (x){ 131 splay(x); 132 if (ch[x][1]){ 133 RG int y=ch[x][1]; while (ch[y][0]) y=ch[y][0]; 134 seg.update(1,1,n,tree.tid[y],tree.ed[y],1); 135 } 136 if (t){ 137 RG int y=t; while (ch[y][0]) y=ch[y][0]; 138 seg.update(1,1,n,tree.tid[y],tree.ed[y],-1); 139 } 140 ch[x][1]=t,t=x,x=fa[x]; 141 } 142 return; 143 } 144 145 }lct; 146 147 il void insert(RG int from,RG int to){ 148 g[++num]=(edge){head[from],to},head[from]=num; return; 149 } 150 151 il int gi(){ 152 RG int x=0,q=1; RG char ch=getchar(); 153 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 154 if (ch=='-') q=-1,ch=getchar(); 155 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 156 return q*x; 157 } 158 159 il void work(){ 160 n=gi(),m=gi(); 161 for (RG int i=1,u,v;i<n;++i) u=gi(),v=gi(),insert(u,v),insert(v,u); 162 tree.dfs1(1,0),tree.dfs2(1,0,1),seg.build(1,1,n); 163 for (RG int i=2;i<=n;++i) lct.fa[i]=tree.fa[i]; 164 for (RG int i=1,type,x,y;i<=m;++i){ 165 type=gi(); if (type==1) x=gi(),lct.access(x); 166 if (type==2){ 167 x=gi(),y=gi(); RG int Lca=tree.lca(x,y); 168 printf("%d\n",seg.ask(x)+seg.ask(y)-2*seg.ask(Lca)+1); 169 } 170 if (type==3) x=gi(),printf("%d\n",seg.querymax(1,1,n,tree.tid[x],tree.ed[x])); 171 } 172 return; 173 } 174 175 int main(){ 176 File("paint"); 177 work(); 178 return 0; 179 }