码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj4817 [Sdoi2017]树点涂色

时间:2017-04-12 19:56:41      阅读:322      评论:0      收藏:0      [点我收藏+]

标签:class   stdout   线段   代码   open   ace   树链剖分   style   stream   

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

 

正解:$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 }

 

bzoj4817 [Sdoi2017]树点涂色

标签:class   stdout   线段   代码   open   ace   树链剖分   style   stream   

原文地址:http://www.cnblogs.com/wfj2048/p/6700710.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!