hihoCoder1576 子樹中的最小權值 dfs序+線段樹

題目:

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;
}
發佈了601 篇原創文章 · 獲贊 25 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章