C. 树(dfs)

题目描述


本题作者交了15次终于过了
首先这道题肯定是用dfs做
但是这道题涉及换根问题
其实换根并不是很难想,想通了挺简单的
首先画个图

有点丑QAQ没关系就这样吧
开始根节点是1
当他换根后设根为rt
要求以点x为根的子树的最小值
分情况讨论
1.当rt=x时,直接输出整棵树的最小值
2.当例如rt=8,x=2时,需要rt往上跳至y=6(也就是2的下一层)
此时求的最小值就是整棵树的范围减去跳至的点的范围(dfs里可以求)in[i]表示i的dfs序
out[i]表示i的最后一个孩子的dfs序(比如in[2]=2,out[2]=8)。
也就是求min(1到in[y]-1,out[y]+1到n)。
3.rt和x不影响,比如rt=2,x=9.
此时直接按原树求就行
dfs不懂的可以先学习一下dfs

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson (id << 1)
#define rson (id << 1 | 1)

const int maxn=1e6+10;
int h[maxn],to[maxn*2],nxt[maxn*2],tot;
int n,q,rt=1,cnt,f[maxn][30],dep[maxn];
int in[maxn],out[maxn],a[maxn],b[maxn];
struct stu
{
	int l,r;
	int min;
}tree[maxn*4];

void addedge(int x,int y)
{
	to[++tot]=y;
	nxt[tot]=h[x];
	h[x]=tot;
}

void dfs(int x,int fa)
{
	a[++cnt]=b[x];
	in[x]=cnt;
	dep[x]=dep[fa]+1;
	f[x][0]=fa;
	for(int j=1;j<30;j++)
	{
		f[x][j]=f[f[x][j-1]][j-1];
	}
	for(int i=h[x];i;i=nxt[i])
	{
		int k=to[i];
		if(k!=fa) dfs(k,x);
	}
	out[x]=cnt;
}

void pushup(int id)//回溯更新父节点 
{
	tree[id].min=min(tree[lson].min,tree[rson].min);
}

void Build(int id,int l,int r)//建树 
{
	tree[id].l=l;
	tree[id].r=r;
	if(l==r)
	{
		tree[id].min=a[l];
		return;
	}
	int mid=((ll)l+r)>>1;
	Build(lson,l,mid);
	Build(rson,mid+1,r);
	pushup(id);
}

void Update(int id,int pos,int val)//单点更新 
{
	if(tree[id].l==tree[id].r)
	{
		tree[id].min=val; 
		return;
	}
	int mid=((ll)tree[id].l+tree[id].r) >> 1;
	if(pos<=mid) Update(lson,pos,val);
	else Update(rson,pos,val);
	pushup(id);
}

int Query(int id,int l,int r)//查询区间最小值
{
	if(r<l) return maxn;
	if(l<=tree[id].l&&tree[id].r<=r)
		return tree[id].min;
	int mid=((ll)tree[id].l+tree[id].r)>>1;
	if(r<=mid) return Query(lson,l,r);
	else if(l>mid) return Query(rson,l,r);
	else return min(Query(lson,l,mid),Query(rson,mid+1,r));
}

int main()
{
	scanf("%d%d",&n,&q);
	int x,y;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&x,&b[i]);
		addedge(x,i);
	}
	dfs(1,0);
	Build(1,1,n);
	char s;
	for(int i=1;i<=q;i++)
	{
		scanf(" %c",&s);
		if(s=='Q')
		{
			scanf("%d",&x);
			if(rt==x) printf("%d\n",tree[1].min);
			else if(in[x]<=in[rt]&&out[x]>=out[rt])
			{
				int d=dep[rt]-dep[x]-1;
				y=rt;
				for(int j=0;j<30;j++)
				{
					if(d&(1<<j))
					{
						y=f[y][j];
					}
				}
				printf("%d\n",min(Query(1,1,in[y]-1),Query(1,out[y]+1,n)));
			}
			else
			{
				printf("%d\n",Query(1,in[x],out[x]));
			}
		}
		else if(s=='V')
		{
			scanf("%d%d",&x,&y);
			Update(1,in[x],y);
		}
		else if(s=='E')
		{
			scanf("%d",&x);
			rt=x;
		}
	}
	
	return 0;
}
posted @ 2024-03-19 11:13  晨曦ccx  阅读(13)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end