【HIHOCODER 1576】 子树中的最小权值(线段树维护DFS序)
2017-09-19 18:02
513 查看
描述
给定一棵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 ,b ,l ,r ,head ; struct Edge{ int next,to; }Path ; 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; }
相关文章推荐
- HihoCoder1576 子树中的最小权值( dfs序 +线段树 || 树剖)
- hihoCoder1576 子树中的最小权值 dfs序+线段树
- hiho1576 子树中的最小权值【dfs序】
- hihocoder#1576 : 子树中的最小权值(dfs序+线段树)
- [LCT维护最小生成树 || CDQ分治 || 线段树 并查集 dfs树] Codeforces 603E #334 (Div. 1) E. Pastoral Oddities
- 树链剖分-链的剖分(线段树维护边权值的更新)
- HDU-3974-Assign the task(线段树维护dfs序)
- [CSU - 1811 (湖南省赛16)] Tree Intersection (dfs序维护子树+离线询问+树状数组)
- CS R22 C(dfs暴力),D(字符串循环节,模拟),E(贪心+线段树维护)
- HDU.5692 Snacks ( DFS序 线段树维护最大值 )
- hdu5323 给出左右边界,求出线段树最小的大小(暴力dfs搜索)
- hihocoder - 股票价格3 - 维护栈 & 线段树
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
- hdu 2242 无向图/求用桥一分为二后使俩个bcc点权值和之差最小并输出 /缩点+2次新图dfs
- [DFS序列+线段树维护区间标记]ZOJ3686 A Simple Tree Problem
- [树状数组套权值线段树 || 分块] BZOJ 2120 数颜色 & BZOJ 2453 维护队列
- hdu 2242 无向图/求用桥一分为二后使俩个bcc点权值和之差最小并输出 /缩点+2次新图dfs
- 【POJ 3321】【dfs序(讲解)+(树状数组或者线段树)】Apple Tree【给你一颗树,最初每个节点上都有一个苹果,有两种操作单点修改和查询子树的苹果个数】
- 2015 年 蓝桥杯 A 组 C/C++ 第十题 灾后重建 【最小生成树 + LCA倍增 + 线段树维护区间max】
- 【Educational Codeforces Round 6E】【线段树 dfs序】New Year Tree 子树颜色修改子树颜色数