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
--by BZOJ
http://www.lydsy.com/JudgeOnline/problem.php?id=4817
大概自己也没想到会回来写这道题吧。
一直对之前见到的,没做出来的题挺抵触的,
不过这是不对的,
题做不出来,也正常,
谁还能把所有的题全做出来呢,
况且,我见到这个题时还不会LCT,
我当时已经打出了树链剖分做法的全部了,
当然爆了一两个点的栈,SD的省选嘛,
然而自己弱是不应该找理由的,
题做不出来就是弱,
没理由的,
那就不应该逃避了,
那么,如果我没有死,你们都将看到我;
如果用LCT记录颜色个数的话,会非常僵,大概只能解决树链剖分解决的问题,
也就是操作三之外的;
但在观察每一个时期树上的颜色情况,发现与LCT的结构类似;
于是考虑利用LCT的结构维护颜色;
对于一二操作;
一就是从某点ACCESS;
二就是从某点空跑ACCESS而不改变splay的组成;
考虑一对三的影响:
发现在ACCESS连接两个点时,父方的点的原儿子的子树到根的颜色数+1,儿子方的点自己的子树颜色树减一;
维护线段树即可;
代码:
1 #include<cstdio> 2 using namespace std; 3 int max[400010],mark[400010],rank[100010],dep[100010],size[100010],a[100010]; 4 struct dt{ 5 int fa,ch[2]; 6 }data[100010]; 7 struct ss{ 8 int to,next; 9 }e[200010]; 10 int first[100010],num; 11 int n,m; 12 void build(int ,int ); 13 void dfs(int ,int ,int ); 14 void builine(int ,int ,int ); 15 void access(int ); 16 int find_top(int ); 17 void splay(int ); 18 void roll(int ); 19 void find(int ,int ); 20 void add(int ,int ,int ,int ,int ,int ); 21 int ans(int ,int ,int ,int ,int ); 22 void down(int ); 23 inline void in(int &ans) 24 { 25 ans=0;bool p=false;char ch=getchar(); 26 while((ch>'9' || ch<'0')&&ch!='-') ch=getchar(); 27 if(ch=='-') p=true,ch=getchar(); 28 while(ch<='9'&&ch>='0') ans=ans*10+ch-'0',ch=getchar(); 29 if(p) ans=-ans; 30 } 31 int main() 32 { 33 int i,j,k,x,y; 34 in(n),in(m); 35 for(i=1;i<=n-1;i++){ 36 in(j),in(k); 37 build(j,k);build(k,j); 38 } 39 num=0;dfs(1,1,0); 40 num=0;builine(1,n,1); 41 for(i=1;i<=m;i++){ 42 in(j); 43 if(j==1){ 44 in(x); 45 access(x); 46 } 47 if(j==2){ 48 in(x),in(y); 49 find(x,y); 50 } 51 if(j==3){ 52 in(x); 53 y=ans(1,n,1,rank[x],rank[x]+size[x]-1); 54 printf("%d\n",y); 55 } 56 } 57 return 0; 58 } 59 void build(int f,int t){ 60 e[++num].next=first[f]; 61 e[num].to=t; 62 first[f]=num; 63 } 64 void dfs(int now,int d,int fa){ 65 int i; 66 dep[now]=d;size[now]=1;rank[now]=++num;a[num]=now;data[now].fa=fa; 67 for(i=first[now];i;i=e[i].next) 68 if(e[i].to!=fa){ 69 dfs(e[i].to,d+1,now); 70 size[now]+=size[e[i].to]; 71 } 72 } 73 void builine(int l,int r,int nu){ 74 if(l==r){ 75 max[nu]=dep[a[++num]]; 76 return ; 77 } 78 int mid=(l+r)>>1; 79 builine(l,mid,nu<<1); 80 builine(mid+1,r,nu<<1|1); 81 max[nu]=max[nu<<1]>max[nu<<1|1]?max[nu<<1]:max[nu<<1|1]; 82 } 83 void access(int x){ 84 int y=0,z; 85 while(x){ 86 splay(x);z=find_top(y); 87 if(z)add(1,n,1,rank[z],rank[z]+size[z]-1,-1); 88 z=data[x].ch[1]; 89 data[x].ch[1]=y; 90 y=x;x=data[x].fa; 91 z=find_top(z); 92 if(z)add(1,n,1,rank[z],rank[z]+size[z]-1,1); 93 } 94 } 95 int find_top(int x){ 96 splay(x); 97 while(data[x].ch[0]) 98 x=data[x].ch[0]; 99 return x; 100 } 101 void splay(int x){ 102 if(!x)return ; 103 int fa,fafa; 104 fa=data[x].fa;fafa=data[fa].fa; 105 for(;data[fa].ch[0]==x||data[fa].ch[1]==x;roll(x),fa=data[x].fa,fafa=data[fa].fa){ 106 if(data[fafa].ch[0]==fa||data[fafa].ch[1]==fa){ 107 if((data[fafa].ch[1]==fa)^(data[fa].ch[1]==x)) 108 roll(x); 109 else 110 roll(fa); 111 } 112 } 113 } 114 void roll(int now){ 115 int fa=data[now].fa,fafa=data[fa].fa,wh=data[fa].ch[1]==now; 116 data[fa].ch[wh]=data[now].ch[wh^1];data[data[fa].ch[wh]].fa=fa; 117 data[now].ch[wh^1]=fa;data[fa].fa=now; 118 data[now].fa=fafa; 119 if (data[fafa].ch[0]==fa||data[fafa].ch[1]==fa) 120 data[fafa].ch[data[fafa].ch[1]==fa]=now; 121 } 122 void find(int x,int y){ 123 int ans=1; 124 x=find_top(x);y=find_top(y); 125 while(x!=y){ 126 if(dep[x]>dep[y]){ 127 splay(x);x=find_top(data[x].fa);ans++; 128 } 129 else{ 130 splay(y);y=find_top(data[y].fa);ans++; 131 } 132 } 133 printf("%d\n",ans); 134 } 135 void add(int l,int r,int nu,int L,int R,int x){ 136 if(L<=l&&r<=R){ 137 max[nu]+=x; 138 mark[nu]+=x; 139 return ; 140 } 141 int mid=(l+r)>>1; 142 down(nu); 143 if(L<=mid) 144 add(l,mid,nu<<1,L,R,x); 145 if(R>mid) 146 add(mid+1,r,nu<<1|1,L,R,x); 147 max[nu]=max[nu<<1]>max[nu<<1|1]?max[nu<<1]:max[nu<<1|1]; 148 } 149 int ans(int l,int r,int nu,int L,int R){ 150 if(L<=l&&r<=R) 151 return max[nu]; 152 int mid=(l+r)>>1,lm=0,rm=0; 153 down(nu); 154 if(L<=mid) 155 lm=ans(l,mid,nu<<1,L,R); 156 if(R>mid) 157 rm=ans(mid+1,r,nu<<1|1,L,R); 158 if(lm>rm)return lm; 159 return rm; 160 } 161 void down(int nu){ 162 if(!mark[nu])return; 163 max[nu<<1]+=mark[nu];max[nu<<1|1]+=mark[nu]; 164 mark[nu<<1]+=mark[nu];mark[nu<<1|1]+=mark[nu]; 165 mark[nu]=0; 166 }