4817: [Sdoi2017]树点涂色
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 515 Solved: 302
[Submit][Status][Discuss]
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
思路{
双倍经验题,同BZOJ3779
具体来说的话查询路径间的权值就是拿$Ans_x+Ans_y-2*Ans_{lca}+1$。
线段树大力搞一下就可以了。
}
#include<bits/stdc++.h> #define LL long long #define RG register #define il inline #define N 100010 using namespace std; namespace tree{ #define rs ((o<<1)|1) #define ls (o<<1) #define mid ((l+r)>>1) int Max[N*4],lazy[N*4]; void down(int o){ if(lazy[o]){ lazy[rs]+=lazy[o],lazy[ls]+=lazy[o]; Max[rs]+=lazy[o],Max[ls]+=lazy[o]; lazy[o]=0; } } void modify(int o,int l,int r,int L,int R,int num){ if(l>=L&&r<=R){Max[o]+=num,lazy[o]+=num;return;} down(o); if(mid<L)modify(rs,mid+1,r,L,R,num); else if(mid>=R)modify(ls,l,mid,L,R,num); else modify(rs,mid+1,r,l,R,num),modify(ls,l,mid,L,R,num); Max[o]=max(Max[rs],Max[ls]); } int query(int o,int l,int r,int L,int R){ if(l>=L&&r<=R)return Max[o]; down(o); if(mid<L)return query(rs,mid+1,r,L,R); else if(mid>=R)return query(ls,l,mid,L,R); else return max(query(rs,mid+1,r,L,R),query(ls,l,mid,L,R)); } } struct ed{int nxt,to;}e[N*2]; int f[19][N],head[N],tot,dfn[N],til[N],id,n,q,fa[N],ch[N][2],dep[N],st[N]; void link(int u,int v){e[tot].nxt=head[u];e[tot].to=v;head[u]=tot++;} void dfs(int u,int faa){fa[u]=faa; dep[u]=dep[faa]+1;dfn[u]=++id;tree::modify(1,1,n,dfn[u],dfn[u],dep[u]); f[0][u]=faa;for(int i=1;i<=18;++i)f[i][u]=f[i-1][f[i-1][u]]; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to;if(v==faa)continue; dfs(v,u); }til[u]=id; } int lca(int x,int y){ if(dep[x]<dep[y])swap(x,y);int de=dep[x]-dep[y]; for(int i=0;i<=18;++i)if((1<<i)&de)x=f[i][x]; if(x!=y){ for(int i=18;i!=-1;i--)if(f[i][x]!=f[i][y])x=f[i][x],y=f[i][y]; x=f[0][x]; }return x; } bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} void Rotate(int x){ int y=fa[x],z=fa[y]; int l=(ch[y][1]==x),r=l^1; if(!isroot(y))ch[z][ch[z][1]==y]=x; ch[y][l]=ch[x][r];fa[ch[x][r]]=y; ch[x][r]=y;fa[x]=z,fa[y]=x; } void Splay(int x){ int y(x),z; while(!isroot(x)){ y=fa[x],z=fa[y]; if(!isroot(y)){ if(ch[z][0]==y^ch[y][0]==x)Rotate(x); else Rotate(y); }Rotate(x); } } int find(int x){ while(ch[x][0])x=ch[x][0]; return x; } void access(int x){ int t(0); while(x){ Splay(x); if(t){ int u=find(t); tree::modify(1,1,n,dfn[u],til[u],-1); } if(ch[x][1]){ int u=find(ch[x][1]); tree::modify(1,1,n,dfn[u],til[u],1); } ch[x][1]=t,t=x,x=fa[x]; } } int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); memset(head,-1,sizeof(head)); scanf("%d%d",&n,&q); for(int i=1;i<n;++i){int u,v;scanf("%d%d",&u,&v),link(u,v),link(v,u);} dfs(1,1);int flag,x,y;fa[1]=0; using namespace tree; for(int i=1;i<=q;++i){ scanf("%d%d",&flag,&x); if(flag==1)access(x); if(flag==2){ scanf("%d",&y);int Lca=lca(x,y); printf("%d ",query(1,1,n,dfn[x],dfn[x])+query(1,1,n,dfn[y],dfn[y])- 2*query(1,1,n,dfn[Lca],dfn[Lca])+1); } if(flag==3)printf("%d ",query(1,1,n,dfn[x],til[x])); }return 0; }