zoukankan      html  css  js  c++  java
  • 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)

    【BZOJ4817】树点涂色(LCT,线段树,树链剖分)

    题面

    BZOJ

    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

    题解

    很有趣的一道题

    先不考虑第一个操作
    假设我们知道每个点到达根节点的答案(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
    ",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
    ",QueryMx(1,1,n,dfn[u],low[u]));
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    java mail实现Email的发送,完整代码
    Android NetworkOnMainThreadException异常
    Anguler Js 表单验证(邮箱)
    Android 调用系统邮件,发送邮件到指定邮箱
    Android 解决ScrollView下嵌套ListView进页面不在顶部的问题
    Eclipse 出错 Error:Could not create the Java Virtual Machine Error:A fatal exception has occurred
    Eclipse "Could not create java virtual machine"的问题解决
    Elasticsearch之watcher(告警)插件安装之后的浏览详解
    Elasticsearch之shield(权限)插件安装之后的浏览详解
    Elasticsearch之源码分析(shard分片规则)
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8640338.html
Copyright © 2011-2022 走看看