您的位置:首页 > 其它

hihocoder#1576 : 子树中的最小权值(dfs序+线段树)

2017-09-20 12:54 351 查看
时间限制:10000ms
单点时限:1000ms
内存限制:256MB


描述

给定一棵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序+线段树。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6+10;
struct lenka
{
int ans,l,r;
}a[MAX<<2];
vector<int>e[MAX];
int L[MAX],R[MAX],num[MAX];
int tot=0,A[MAX];
void dfs(int k)
{
L[k]=++tot;
num[tot]=A[k];
for(int i=0;i<e[k].size();i++)
{
int nex=e[k][i];
dfs(nex);
}
R[k]=tot;
}
void build(int k,int l,int r)
{
a[k].l=l,a[k].r=r;
if(l==r){a[k].ans=num[l];return;}
build(2*k,l,(l+r)/2);
build(2*k+1,(l+r)/2+1,r);
a[k].ans=min(a[2*k].ans,a[2*k+1].ans);
}
void change(int k,int x,int tag)
{
if(a[k].l==x&&a[k].r==x)
{
a[k].ans=tag;
return;
}
if(x<=a[2*k].r)change(2*k,x,tag);
if(x>=a[2*k+1].l)change(2*k+1,x,tag);
a[k].ans=min(a[2*k].ans,a[2*k+1].ans);
}
int ask(int k,int l,int r)
{
if(a[k].l==l&&a[k].r==r)return a[k].ans;
if(r<=a[2*k].r)return ask(2*k,l,r);
else if(l>=a[2*k+1].l)return ask(2*k+1,l,r);
return min(ask(2*k,l,a[2*k].r),ask(2*k+1,a[2*k+1].l,r));
}
int main()
{
int n,T;
scanf("%d",&n);
for(int i=1;i<=n;i++)e[i].clear();
for(int i=1;i<=n;i++)scanf("%d",&A[i]);
for(int x,i=2;i<=n;i++)
{
scanf("%d",&x);
e[x].push_back(i);
}
dfs(1);
build(1,1,n);
scanf("%d",&T);
while(T--)
{
int op,x,y;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&x,&y);
change(1,L[x],y);
}
else
{
scanf("%d",&x);
printf("%d\n",ask(1,L[x],R[x]));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: