SDOI2017 树点涂色——LCT the END

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

Sample Output

3
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 }

 

posted @ 2017-07-03 18:53  F.W.Nietzsche  阅读(187)  评论(0编辑  收藏  举报