【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
2018-03-24 17:20
471 查看
题面
BZOJDescription
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 61 2
2 3
3 4
3 5
2 4 5
3 3
1 4
2 4 5
1 5
2 4 5
Sample Output
34
2
2
题解
很有趣的一道题先不考虑第一个操作
假设我们知道每个点到达根节点的答案f(i)
那么,第二个询问就是平时的u+v−2lca的操作
也就是f(u)+f(v)−2f(lca)+1。
加一的原因是lca的颜色被多减了一次
第三个操作?直接求子树最大值
转换成dfs序上的区间最大值
很显然线段树
初始状态下,线段树的权值就是树的深度dep
好的,现在看第一个操作
处理到根的链?这个操作迷之熟悉。
十分类似于LCT的access,也就是将x到根节点变为重链
这个操作呢?似乎是一样的。
那么考虑一下在access的操作中对于答案的影响
如果断开了右儿子的链,意味着右儿子需要额外的多跳一次
给右儿子所在的子树的答案加一
而接上来的右子树显然会少跳一次
那么给新的右子树的答案减一
这样所有的问题就解决完了
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MAX 111111 #define lson (now<<1) #define rson (now<<1|1) inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } struct Node{int ch[2],ff;}t[MAX]; struct Line{int v,next;}e[MAX<<1]; int h[MAX],cnt=1,n,m; int fa[MAX],dfn[MAX],low[MAX],tim,dep[MAX]; int size[MAX],hson[MAX],top[MAX],ln[MAX]; void dfs1(int u,int ff) { fa[u]=ff;dep[u]=dep[ff]+1;size[u]=1; for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==ff)continue; dfs1(v,u);size[u]+=size[v]; if(size[v]>size[hson[u]])hson[u]=v; } } void dfs2(int u,int tp) { top[u]=tp;dfn[u]=++tim;ln[tim]=u; if(hson[u])dfs2(hson[u],tp); for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==hson[u]||v==fa[u])continue; dfs2(v,v); } low[u]=tim; } int LCA(int u,int v) { while(top[u]!=top[v]) dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]]; return dep[u]<dep[v]?u:v; } struct SegNode{int v,tg;}T[MAX<<2]; void Build(int now,int l,int r) { if(l==r){T[now].v=dep[ln[l]];return;} int mid=(l+r)>>1; Build(lson,l,mid);Build(rson,mid+1,r); T[now].v=max(T[lson].v,T[rson].v); } void puttag(int now,int w){T[now].tg+=w;T[now].v+=w;} void pushdown(int now){puttag(lson,T[now].tg);puttag(rson,T[now].tg);T[now].tg=0;} void Modify(int now,int l,int r,int L,int R,int w) { if(L<=l&&r<=R){puttag(now,w);return;} int mid=(l+r)>>1;pushdown(now); if(L<=mid)Modify(lson,l,mid,L,R,w); if(R>mid)Modify(rson,mid+1,r,L,R,w); T[now].v=max(T[lson].v,T[rson].v); } int QueryV(int now,int l,int r,int p) { if(l==r)return T[now].v; int mid=(l+r)>>1;pushdown(now); if(p<=mid)return QueryV(lson,l,mid,p); else return QueryV(rson,mid+1,r,p); } int QueryMx(int now,int l,int r,int L,int R) { if(L<=l&&r<=R)return T[now].v; int mid=(l+r)>>1,ret=0;pushdown(now); if(L<=mid)ret=max(ret,QueryMx(lson,l,mid,L,R)); if(R>mid)ret=max(ret,QueryMx(rson,mid+1,r,L,R)); return ret; } inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;} bool isroot(int x){return t[t[x].ff].ch[0]!=x&&t[t[x].ff].ch[1]!=x;} void rotate(int x) { int y=t[x].ff,z=t[y].ff; int k=t[y].ch[1]==x; if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z; t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y; t[x].ch[k^1]=y;t[y].ff=x; } void Splay(int x) { while(!isroot(x)) { int y=t[x].ff,z=t[y].ff; if(!isroot(y)) (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y); rotate(x); } } int findroot(int x){while(t[x].ch[0])x=t[x].ch[0];return x;} void access(int x) { for(int y=0;x;y=x,x=t[x].ff) { Splay(x); if(t[x].ch[1]) { int u=findroot(t[x].ch[1]); Modify(1,1,n,dfn[u],low[u],1); } t[x].ch[1]=y; if(t[x].ch[1]) { int u=findroot(t[x].ch[1]); Modify(1,1,n,dfn[u],low[u],-1); } } } int main() { n=read();m=read(); for(int i=1;i<n;++i) { int u=read(),v=read(); Add(u,v);Add(v,u); } dfs1(1,0);dfs2(1,1); for(int i=2;i<=n;++i)t[i].ff=fa[i]; Build(1,1,n); while(m--) { int opt=read(); if(opt==1)access(read()); else if(opt==2) { int u=read(),v=read(),lca=LCA(u,v); printf("%d\n",QueryV(1,1,n,dfn[u])+QueryV(1,1,n,dfn[v])-2*QueryV(1,1,n,dfn[lca])+1); } else { int u=read(); printf("%d\n",QueryMx(1,1,n,dfn[u],low[u])); } } return 0; }
相关文章推荐
- 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
- 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]
- BZOJ 4817 [LCT][线段树][树链剖分]
- BZOJ 4817 [Sdoi2017]树点涂色 ——LCT 线段树
- 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序
- BZOJ.4817.[SDOI2017]树点涂色(LCT DFS序 线段树)
- [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]
- [LCT] BZOJ 4817 [Sdoi2017]树点涂色
- bzoj 4817: [Sdoi2017]树点涂色 LCT+树链剖分+线段树
- bzoj 4817: [Sdoi2017]树点涂色 link cut tree+线段树+树链剖分
- [LCT] BZOJ4817.[Sdoi2017]树点涂色
- [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)
- [BZOJ4817][SDOI2017]树点涂色(DFS序+LCA+树剖+LCT)
- [Sdoi2017]树点涂色 [lct 线段树]
- 【BZOJ 1180】OTOCI【LCT】&【树链剖分+并查集】
- 【bzoj2243】【树链剖分】【线段树】SDOI2011染色
- Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT
- [BZOJ2325][ZJOI2011][树链剖分][线段树]道馆之战
- BZOJ-2243: [SDOI2011]染色 (树链剖分 入门题 线段树 区间修改查询 维护端点值)
- BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分)(线段树单点修改)