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;
}