【HIHOCODER 1576】 子树中的最小权值(线段树维护DFS序)
描述
给定一棵N个节点的树,编号1~N。其中1号节点是根,并且第i个节点的权值是Vi。
针对这棵树,小Hi会询问小Ho一系列问题。每次小Hi会指定一个节点x,询问小Ho以x为根的子树中,最小的权值是多少。为了增加难度,小Hi可能随时改变其中每个节点的权值。
你能帮助小Ho准确、快速的回答小Hi的问题吗?
输入
第一行一个正整数N。
第二行N个整数,V1, V2, ... VN。
第三行n-1个正整数,第i个数Pi表示第i+1号节点的父结点是第Pi号节点。注意1号节点是根。
第四行一个正整数Q,表示有Q个询问/修改权值。
接下来Q行,每行可能有如下两种输入格式:
1 x u
2 x
第一种表示将第x号节点的权值修改为u
第二种表示询问以第x号节点为根的子树中,最小的权值是多少。
对于30%的数据,1 ≤ N, Q ≤ 1000
对于100%的数据,1 ≤ N, Q ≤ 100000, -109 <= Vi, u <= 109
输出
对于每次询问,输出一个整数表示答案。
样例输入
12
3 5 -1 -2 9 6 2 8 -10 11 8 10
1 1 1 2 4 2 6 7 7 8 8
10
2 3
2 1
2 6
1 11 -5
1 5 -12
2 6
2 4
2 2
2 1
2 7
样例输出
-1
-10
6
-5
-5
-12
-12
-10
题解
只需对这棵树求一个dfs序列,记录一个节点x前一次出现的位置和后一次出现的位置,那么在这个区间之内的节点都是它的子树节点,这样修改和查询都是区间维护,用线段树即可
#include <map>
#include <cmath>
#include <cstdio>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ll long long
#define inf 1000000000
#define PI acos(-1)
#define bug puts("here")
#define REP(i,x,n) for(int i=x;i<=n;i++)
#define DEP(i,n,x) for(int i=n;i>=x;i--)
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void Out(int a){
if(a<0) putchar('-'),a=-a;
if(a>=10) Out(a/10);
putchar(a%10+'0');
}
const int N=1e5+5;
int n,q,x,y,tmp,cnt,tot;
int a[N],b[N],l[N],r[N],head[N];
struct Edge{
int next,to;
}Path[N];
int C[N<<2];
void Addedge(int x,int y){
Path[++cnt]=(Edge){head[x],y};
head[x]=cnt;
}
void dfs(int x){
b[++tot]=x;l[x]=tot;
for(int i=head[x];i;i=Path[i].next){
dfs(Path[i].to);
}
r[x]=tot;
}
void Pushup(int rt) {
C[rt]=min(C[rt<<1],C[rt<<1|1]);
}
void Build(int rt,int l,int r){
if (l==r){
C[rt]=a[b[l]];
return;
}
int mid=(l+r)>>1;
Build(rt<<1,l,mid);Build(rt<<1|1,mid+1,r);
Pushup(rt);
}
void Update(int rt,int pos,int x,int l,int r){
if (l==r){
C[rt]=x;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) Update(rt<<1,pos,x,l,mid);
if(pos>mid) Update(rt<<1|1,pos,x,mid+1,r);
Pushup(rt);
}
int Query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R) return C[rt];
int mid=(l+r)>>1;
int res=inf;
if(L<=mid){res=min(res,Query(rt<<1,l,mid,L,R));}
if(R>mid) {res=min(res,Query(rt<<1|1,mid+1,r,L,R));}
return res;
}
int main(){
n=read();
REP(i,1,n) a[i]=read();
REP(i,2,n){
x=read();
Addedge(x,i);
}
dfs(1);Build(1,1,n);
q=read();
while(q--){
int op=read();
if (op==1)
{
x=read();y=read();
Update(1,l[x],y,1,n);
}else{
x=read();
printf("%d\n",Query(1,1,n,l[x],r[x]));
}
}
return 0;
}