zoukankan      html  css  js  c++  java
  • 【洛谷P3703】树点涂色

    题目

    题目链接:https://www.luogu.com.cn/problem/P3703
    Bob 有一棵 (n) 个点的有根树,其中 (1) 号点是根节点。Bob 在每个点上涂了颜色,并且每个点上的颜色不同。
    定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。
    Bob 可能会进行这几种操作:

    • 1 x 表示把点 (x) 到根节点的路径上所有的点染上一种没有用过的新颜色。
    • 2 x y(x)(y) 的路径的权值。
    • 3 x 在以 (x) 为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。

    Bob 一共会进行 (m) 次操作。
    (1leq n leq 10^5)(1leq m leq 10^5)

    思路

    发现每次修改都是直接把 (x) 到根的路径的颜色全部赋值,然后原来的颜色就失效了,容易发现任意时刻每一个节点最多有一个儿子的颜色与其相同。
    发现这个操作和 LCT 的 access 十分相似,每一个点只可以保留一条实边。
    如果我们把操作一看做将 access((x)),那么一个点的权值就转换为了该点到根节点的虚边的数量。
    在 access 的时候,当我们把 (x) 与其原来的实儿子的边断开时,它实儿子所在子树的权值全部加 (1),连接新的实儿子 (y) 后,(y) 所在子树内的权值全部减 (1)
    那么用一个线段树维护区间和以及区间最大值即可。注意是一个节点所在子树内的权值加减,所以要先 findrt,然后在找到的根节点进行修改。但是 findrt 之后不能 splay,否则会改变 Splay 的形态。
    然后对于操作 (2),答案即为 (x,y) 的权值和减去他们 LCA 的权值的两倍再加上 (1)。操作三直接区间最大值即可。
    时间复杂度 (O(mlog^2n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=100010,LG=18;
    int n,m,tot,head[N],dfn[N],rk[N],siz[N],dep[N],f[N][LG+1];
    
    struct edge
    {
    	int next,to;
    }e[N*2];
    
    void add(int from,int to)
    {
    	e[++tot]=(edge){head[from],to};
    	head[from]=tot;
    }
    
    struct SegTree
    {
    	int maxn[N*4],lazy[N*4];
    	
    	void pushdown(int x)
    	{
    		if (lazy[x])
    		{
    			maxn[x*2]+=lazy[x]; lazy[x*2]+=lazy[x];
    			maxn[x*2+1]+=lazy[x]; lazy[x*2+1]+=lazy[x];
    			lazy[x]=0;
    		}
    	}
    	
    	void pushup(int x)
    	{
    		maxn[x]=max(maxn[x*2],maxn[x*2+1]);
    	}
    	
    	void build(int x,int l,int r)
    	{
    		if (l==r)
    		{
    			maxn[x]=dep[rk[l]];
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(x*2,l,mid); build(x*2+1,mid+1,r);
    		pushup(x);
    	}
    	
    	void update(int x,int l,int r,int ql,int qr,int v)
    	{
    		if (ql<=l && r<=qr)
    		{
    			lazy[x]+=v; maxn[x]+=v;
    			return;
    		}
    		pushdown(x);
    		int mid=(l+r)>>1;
    		if (ql<=mid) update(x*2,l,mid,ql,qr,v);
    		if (qr>mid) update(x*2+1,mid+1,r,ql,qr,v);
    		pushup(x);
    	}
    	
    	int query(int x,int l,int r,int ql,int qr)
    	{
    		if (!l || !r) return 0;
    		if (ql<=l && r<=qr) return maxn[x];
    		pushdown(x);
    		int mid=(l+r)>>1,s=0;
    		if (ql<=mid) s=max(s,query(x*2,l,mid,ql,qr));
    		if (qr>mid) s=max(s,query(x*2+1,mid+1,r,ql,qr));
    		return s;
    	}
    }seg;
    
    struct LCT
    {
    	int fa[N],ch[N][2];
    	
    	bool pos(int x)
    	{
    		return x==ch[fa[x]][1];
    	}
    	
    	bool notrt(int x)
    	{
    		return x==ch[fa[x]][1] || x==ch[fa[x]][0];
    	}
    	
    	void rotate(int x)
    	{
    		int y=fa[x],z=fa[y],k=pos(x),c=ch[x][k^1];
    		if (notrt(y)) ch[z][pos(y)]=x; ch[x][k^1]=y; ch[y][k]=c;
    		if (c) fa[c]=y; fa[y]=x; fa[x]=z;
    	}
    	
    	void splay(int x)
    	{
    		while (notrt(x))
    		{
    			int y=fa[x];
    			if (notrt(y))
    				rotate(pos(x)==pos(y)?y:x);
    			rotate(x);
    		}
    	}
    	
    	int findrt(int x)
    	{
    		splay(x);
    		for (;ch[x][0];x=ch[x][0]) ;
    		return x;
    	}
    	
    	void access(int x)
    	{
    		for (int y=0;x;y=x,x=fa[x])
    		{
    			splay(x);
    			int z=ch[x][1]; ch[x][1]=0;
    			if (z)
    			{
    				int p=findrt(z);
    				seg.update(1,1,n,dfn[p],dfn[p]+siz[p]-1,1);
    			}
    			if (y)
    			{
    				int p=findrt(y);
    				seg.update(1,1,n,dfn[p],dfn[p]+siz[p]-1,-1);
    			}
    			ch[x][1]=y;
    		}
    	}
    }lct;
    
    void dfs(int x,int fa)
    {
    	lct.fa[x]=fa;
    	siz[x]=1; dfn[x]=++tot; rk[tot]=x;
    	f[x][0]=fa; dep[x]=dep[fa]+1;
    	for (int i=1;i<=LG;i++)
    		f[x][i]=f[f[x][i-1]][i-1];
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (v!=fa)
    		{
    			dfs(v,x);
    			siz[x]+=siz[v];
    		}
    	}
    }
    
    int lca(int x,int y)
    {
    	if (dep[x]<dep[y]) swap(x,y);
    	for (int i=LG;i>=0;i--)
    		if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    	if (x==y) return x;
    	for (int i=LG;i>=0;i--)
    		if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);
    	for (int i=1,x,y;i<n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,y); add(y,x);
    	}
    	tot=0; dfs(1,0);
    	seg.build(1,1,n);
    	while (m--)
    	{
    		int opt,x,y;
    		scanf("%d",&opt);
    		if (opt==1)
    		{
    			scanf("%d",&x);
    			lct.access(x);
    		}
    		if (opt==2)
    		{
    			scanf("%d%d",&x,&y);
    			int p=lca(x,y);
    			int s1=seg.query(1,1,n,dfn[x],dfn[x])+seg.query(1,1,n,dfn[y],dfn[y]);
    			int s2=2*seg.query(1,1,n,dfn[p],dfn[p]);
    			printf("%d
    ",s1-s2+1);
    		}
    		if (opt==3)
    		{
    			scanf("%d",&x);
    			printf("%d
    ",seg.query(1,1,n,dfn[x],dfn[x]+siz[x]-1));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java的参数传递是「按值传递」还是「按引用传递」?
    算法08 五大查找之:二叉排序树(BSTree)
    算法07 五大查找之:索引查找
    算法06 五大查找之:二分查找
    Django rest_framework实现RESTful API
    jenkins + pipeline构建自动化部署
    jenkins部署.net平台自动化构建
    python实现编写windows服务
    iis部署python运行环境
    Jenkins执行批处理文件、powershell失败
  • 原文地址:https://www.cnblogs.com/stoorz/p/14245594.html
Copyright © 2011-2022 走看看