題目:
http://hihocoder.com/problemset/problem/1576?sid=1197257
題意:
描述
給定一棵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
輸出
對於每次詢問,輸出一個整數表示答案。
思路:
首先用dfs標號,然後線段樹維護即可
#include <bits/stdc++.h>
using namespace std;
const int N = 100000 + 10, INF = 0x3f3f3f3f;
struct edge
{
int to, next;
}g[N*2];
struct node
{
int l, r, val;
}tr[N*4];
int cnt, head[N];
int tot;
int in[N], out[N];
int a[N], b[N];
void init()
{
cnt = 0;
memset(head, -1, sizeof head);
tot = 0;
}
void add_edge(int v, int u)
{
g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;
}
void dfs(int v, int fa)
{
in[v] = ++tot;
for(int i = head[v]; ~i; i = g[i].next)
{
int u = g[i].to;
if(u == fa) continue;
dfs(u, v);
}
out[v] = tot;
}
void push_up(int k)
{
tr[k].val = min(tr[k<<1].val, tr[k<<1|1].val);
}
void build(int l, int r, int k)
{
tr[k].l = l, tr[k].r = r;
if(l == r)
{
tr[k].val = b[l]; return;
}
int mid = (l + r) >> 1;
build(l, mid, k<<1);
build(mid+1, r, k<<1|1);
push_up(k);
}
void update(int x, int val, int k)
{
if(tr[k].l == tr[k].r && tr[k].l == x)
{
tr[k].val = val; return;
}
int mid = (tr[k].l + tr[k].r) >> 1;
if(x <= mid) update(x, val, k<<1);
else update(x, val, k<<1|1);
push_up(k);
}
int query(int l, int r, int k)
{
if(l <= tr[k].l && tr[k].r <= r)
{
return tr[k].val;
}
int mid = (tr[k].l + tr[k].r) >> 1;
int ans = INF;
if(l <= mid) ans = min(ans, query(l, r, k<<1));
if(r > mid) ans = min(ans, query(l, r, k<<1|1));
return ans;
}
int main()
{
init();
int n, m, opt, x, y;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n-1; i++)
{
scanf("%d", &x);
add_edge(x, i+1);
}
dfs(1, 0);
for(int i = 1; i <= n; i++) b[in[i]] = a[i];
build(1, n, 1);
scanf("%d", &m);
for(int i = 1; i <= m; i++)
{
scanf("%d", &opt);
if(opt == 1)
{
scanf("%d%d", &x, &y);
update(in[x], y, 1);
}
else
{
scanf("%d", &x);
printf("%d\n", query(in[x], out[x], 1));
}
}
return 0;
}