zoukankan      html  css  js  c++  java
  • BZOJ4817[Sdoi2017]树点涂色——LCT+线段树

    题目描述

    Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
    径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
    1 x:
    把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
    2 x y:
    求x到y的路径的权值。
    3 x
    在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
    Bob一共会进行m次操作

    输入

    第一行两个数n,m。
    接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
    接下来m行,表示操作,格式见题目描述
    1<=n,m<=100000

    输出

    每当出现2,3操作,输出一行。
    如果是2操作,输出一个数表示路径的权值
    如果是3操作,输出一个数表示权值的最大值

    样例输入

    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

    样例输出

    3
    4
    2
    2
     
    我们将连续相同颜色的一条链看成一条重链,可以发现修改操作其实就是$LCT$里的$access$操作。
    那么每个节点到根的权值就是这个点到根路径上的重链数。
    考虑用线段树维护出每个点到根的权值,每次修改时假设路径上$x->fa$的边是轻边,$fa$的重儿子是$son$,那么就将$son$子树中所有点的答案$+1$,$x$子树中所有点答案$-1$,然后将$x$变为$fa$的重儿子。在$access$时完成子树修改操作即可。
    对于查询$x$到$y$的路径权值,就是$v[x]+v[y]-2v[lca]+1$。
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<bitset>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int c[100010][2];
    int fa[100010];
    int tag[400010];
    int f[100010][18];
    int dep[100010];
    int mx[400010];
    int dfn;
    int tot;
    int x,y;
    int n,m;
    int opt;
    int head[100010];
    int next[200010];
    int to[200010];
    int q[100010];
    int s[100010];
    int t[100010];
    void add(int x,int y)
    {
    	next[++tot]=head[x];
    	head[x]=tot;
    	to[tot]=y;
    }
    void pushup(int rt)
    {
    	mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
    }
    void pushdown(int rt)
    {
    	if(tag[rt])
    	{
    		tag[rt<<1]+=tag[rt];
    		tag[rt<<1|1]+=tag[rt];
    		mx[rt<<1]+=tag[rt];
    		mx[rt<<1|1]+=tag[rt];
    		tag[rt]=0;
    	}
    }
    void build(int rt,int l,int r)
    {
    	if(l==r)
    	{
    		mx[rt]=dep[q[l]];
    		return ;
    	}
    	int mid=(l+r)>>1;
    	build(rt<<1,l,mid);
    	build(rt<<1|1,mid+1,r);
    	pushup(rt);
    }
    void change(int rt,int l,int r,int L,int R,int v)
    {
    	if(L<=l&&r<=R)
    	{
    		tag[rt]+=v;
    		mx[rt]+=v;
    		return ;
    	}
    	pushdown(rt);
    	int mid=(l+r)>>1;
    	if(L<=mid)
    	{
    		change(rt<<1,l,mid,L,R,v);
    	}
    	if(R>mid)
    	{
    		change(rt<<1|1,mid+1,r,L,R,v);
    	}
    	pushup(rt);
    }
    int query(int rt,int l,int r,int L,int R)
    {
    	if(L<=l&&r<=R)
    	{
    		return mx[rt];
    	}
    	pushdown(rt);
    	int mid=(l+r)>>1;
    	int res=0;
    	if(L<=mid)
    	{
    		res=max(res,query(rt<<1,l,mid,L,R));
    	}
    	if(R>mid)
    	{
    		res=max(res,query(rt<<1|1,mid+1,r,L,R));
    	}
    	return res;
    }
    int ask(int rt,int l,int r,int k)
    {
    	if(l==r)
    	{
    		return mx[rt];
    	}
    	pushdown(rt);
    	int mid=(l+r)>>1;
    	if(k<=mid)
    	{
    		return ask(rt<<1,l,mid,k);
    	}
    	else
    	{
    		return ask(rt<<1|1,mid+1,r,k);
    	}
    }
    bool is_root(int rt)
    {
    	return rt!=c[fa[rt]][0]&&rt!=c[fa[rt]][1];
    }
    bool get(int rt)
    {
    	return rt==c[fa[rt]][1];
    }
    void rotate(int rt)
    {
    	int x=fa[rt];
    	int y=fa[x];
    	int k=get(rt);
    	if(!is_root(x))
    	{
    		c[y][get(x)]=rt;
    	}
    	c[x][k]=c[rt][k^1];
    	fa[c[rt][k^1]]=x;
    	c[rt][k^1]=x;
    	fa[x]=rt;
    	fa[rt]=y;
    }
    void splay(int rt)
    {
    	for(int x;!is_root(rt);rotate(rt))
    	{
    		if(!is_root(x=fa[rt]))
    		{
    			rotate(get(x)==get(rt)?x:rt);
    		}
    	}
    }
    void link(int x,int y)
    {
    	fa[x]=y;
    }
    int find(int rt)
    {
    	while(c[rt][0])
    	{
    		rt=c[rt][0];
    	}
    	return rt;
    }
    void access(int rt)
    {
    	for(int x=0;rt;x=rt,rt=fa[rt])
    	{
    		splay(rt);
    		if(x)
    		{
    			int son=find(x);
    			change(1,1,n,s[son],t[son],-1);
    		}
    		if(c[rt][1])
    		{
    			int son=find(c[rt][1]);
    			change(1,1,n,s[son],t[son],1);
    		}
    		c[rt][1]=x;
    	}
    }
    void dfs(int x)
    {
    	s[x]=++dfn;
    	q[dfn]=x;
    	for(int i=1;i<=17;i++)
    	{
    		f[x][i]=f[f[x][i-1]][i-1];
    	}
    	for(int i=head[x];i;i=next[i])
    	{
    		if(to[i]!=f[x][0])
    		{
    			f[to[i]][0]=x;
    			link(to[i],x);
    			dep[to[i]]=dep[x]+1;
    			dfs(to[i]);
    		}
    	}
    	t[x]=dfn;
    }
    int lca(int x,int y)
    {
    	if(dep[x]<dep[y])
    	{
    		swap(x,y);
    	}
    	int d=dep[x]-dep[y];
    	for(int i=0;i<=17;i++)
    	{
    		if(d&(1<<i))
    		{
    			x=f[x][i];
    		}
    	}
    	if(x==y)
    	{
    		return x;
    	}
    	for(int i=17;i>=0;i--)
    	{
    		if(f[x][i]!=f[y][i])
    		{
    			x=f[x][i];
    			y=f[y][i];
    		}
    	}
    	return f[x][0];
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		add(y,x);
    	}
    	dep[1]=1;
    	dfs(1);
    	build(1,1,n);
    	while(m--)
    	{
    		scanf("%d",&opt);
    		if(opt==1)
    		{
    			scanf("%d",&x);
    			access(x);
    		}
    		else if(opt==2)
    		{
    			scanf("%d%d",&x,&y);
    			int anc=lca(x,y);
    			int ans=ask(1,1,n,s[x])+ask(1,1,n,s[y])-2*ask(1,1,n,s[anc])+1;
    			printf("%d
    ",ans);
    		}
    		else
    		{
    			scanf("%d",&x);
    			printf("%d
    ",query(1,1,n,s[x],t[x]));
    		}
    	}
    }
  • 相关阅读:
    替换指定串函数
    实现超级链接
    面向对象的关系数据库设计
    SQL语句的添加、删除、修改多种方法
    InfoWorld2008最佳开源软件大奖
    判断字符是否是汉字
    delphi指针
    项目经理要“三心二意”
    Linq查询Specified cast is not valid异常的常见原因
    SQL SERVER数据库同步示例
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10650810.html
Copyright © 2011-2022 走看看