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 }

 

posted @ 2018-12-22 20:31  guapisolo  阅读(229)  评论(0编辑  收藏  举报