HihoCoder1576 子树中的最小权值( dfs序 +线段树 || 树剖)
2018-01-10 21:04
453 查看
给定一棵N个节点的树,编号1~N。其中1号节点是根,并且第i个节点的权值是Vi。
针对这棵树,小Hi会询问小Ho一系列问题。每次小Hi会指定一个节点x,询问小Ho以x为根的子树中,最小的权值是多少。为了增加难度,小Hi可能随时改变其中每个节点的权值。
你能帮助小Ho准确、快速的回答小Hi的问题吗?
Input
第一行一个正整数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
Output
对于每次询问,输出一个整数表示答案。
Sample Input
Sample Output
求子树的最小值。单点更新。显然是dfs序,然后按顺序存入线段树里面,由于一颗子树在线段树里的位置相邻,我们可以利用起线段树。
没必要写树剖。由于今天做的几道XOR题太难,我已经疯了。。。
针对这棵树,小Hi会询问小Ho一系列问题。每次小Hi会指定一个节点x,询问小Ho以x为根的子树中,最小的权值是多少。为了增加难度,小Hi可能随时改变其中每个节点的权值。
你能帮助小Ho准确、快速的回答小Hi的问题吗?
Input
第一行一个正整数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
Output
对于每次询问,输出一个整数表示答案。
Sample Input
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
Sample Output
-1 -10 6 -5 -5 -12 -12 -10
求子树的最小值。单点更新。显然是dfs序,然后按顺序存入线段树里面,由于一颗子树在线段树里的位置相邻,我们可以利用起线段树。
没必要写树剖。由于今天做的几道XOR题太难,我已经疯了。。。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=400010; int sa[maxn],Rank[maxn]; int Laxt[maxn],Next[maxn],To[maxn],cnt; int fa[maxn],a[maxn],sz[maxn],tot=1; int ch[maxn][2],Min[maxn]; void add(int u,int v) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } int dfs(int u) { sz[u]=1; for(int i=Laxt[u];i;i=Next[i]){ int v=To[i]; sa[v]=++tot; Rank[tot]=v; sz[u]+=dfs(v); } return sz[u]; } void update(int Now) { Min[Now]=min(Min[Now<<1],Min[Now<<1|1]); } void build(int Now,int L,int R) { if(L==R) { Min[Now]=a[Rank[L]]; return ;} int Mid=(L+R)>>1; build(Now<<1,L,Mid); build(Now<<1|1,Mid+1,R); update(Now); } int query(int Now,int L,int R,int l,int r) { if(l<=L&&r>=R) return Min[Now]; int Mid=(L+R)>>1; if(r<=Mid) return query(Now<<1,L,Mid,l,r); else if(l>Mid) return query(Now<<1|1,Mid+1,R,l,r); else return min(query(Now<<1,L,Mid,l,Mid),query(Now<<1|1,Mid+1,R,Mid+1,r)); } void change(int Now,int L,int R,int x,int val) { if(L==R) { Min[Now]=val;return ;} int Mid=(L+R)>>1; if(x<=Mid) change(Now<<1,L,Mid,x,val); else change(Now<<1|1,Mid+1,R,x,val); update(Now); } int main() { int i,j,n,q,x,y,opt; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=2;i<=n;i++) scanf("%d",&fa[i]),add(fa[i],i); sa[1]=1; Rank[1]=1; dfs(1); build(1,1,n); scanf("%d",&q); for(i=1;i<=q;i++){ scanf("%d",&opt); if(opt==1) scanf("%d%d",&x,&y),change(1,1,n,sa[x],y); else { scanf("%d",&x); printf("%d\n",query(1,1,n,sa[x],sa[x]+sz[x]-1)); } } return 0; }
相关文章推荐
- 【HIHOCODER 1576】 子树中的最小权值(线段树维护DFS序)
- hiho1576 子树中的最小权值【dfs序】
- hihoCoder1576 子树中的最小权值 dfs序+线段树
- hihocoder#1576 : 子树中的最小权值(dfs序+线段树)
- hihoCoder 1077 RMQ问题再临-线段树 单点修改,求区间最小值
- 【POJ 3321】【dfs序(讲解)+(树状数组或者线段树)】Apple Tree【给你一颗树,最初每个节点上都有一个苹果,有两种操作单点修改和查询子树的苹果个数】
- [LCT维护最小生成树 || CDQ分治 || 线段树 并查集 dfs树] Codeforces 603E #334 (Div. 1) E. Pastoral Oddities
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
- hdu 2242 无向图/求用桥一分为二后使俩个bcc点权值和之差最小并输出 /缩点+2次新图dfs
- 【Educational Codeforces Round 6E】【线段树 dfs序】New Year Tree 子树颜色修改子树颜色数
- hdu 2242 无向图/求用桥一分为二后使俩个bcc点权值和之差最小并输出 /缩点+2次新图dfs
- hdu5323 给出左右边界,求出线段树最小的大小(暴力dfs搜索)
- hihoCoder 1586 Minimum 【线段树】 (ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛)
- 【bzoj3307】雨天的尾巴 权值线段树合并
- Tarjan无向图最小权值割边
- CodeForces - 557CArthur and Table(贪心+桶排或权值线段树)
- POJ 3264 Balanced Lineup(线段树点修改 查询最大最小总和 修改 增加/模板)
- 洛谷P2982 [USACO10FEB]慢下来Slowing down(线段树 DFS序 区间增减 单点查询)
- poj 2374 求横向距离和最小 线段树 + 动态规划
- poj 2516 Minimum Cost KM算法 最小权值匹配