3306: 树(线段树)

3306: 树

1.思路

  首先dfs整颗树将树转换线性结构,前两个操作比较简单,然后主要是对于操作三,有三种情况:

    1.x=rt,那么我们直接求出整颗树中的最小值就是答案;

    2.x在原树中为rt的祖先节点,那么我们首先求出从x到rt路径上的x的第一个节点y,那么答案就是除了以y为根的子树的其他所有节点的最小值;

    3.对于除了以上两种情况,直接求出以x为根的子树的最小值即为答案.

    

2.代码

 

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
#define ls rt<<1
#define rs rt<<1|1

struct Edge{
    int to, next;  
};

Edge e[N];
int head[N];
int dep[N];
int tot;

void addEdge(int u, int v) {
    e[++tot] = Edge{v, head[u]};
    head[u] = tot;
}

int a[N], b[N];
int l[N], r[N];
int dfs_clock;
int f[N][20];
void dfs(int u) {
    l[u] = ++ dfs_clock;
    a[dfs_clock] = b[u];
    for(int i = head[u]; i; i = e[i].next) {
        int to = e[i].to;
        dep[to] = dep[u] + 1;
        f[to][0] = u;
        dfs(to);
    }
    r[u] = dfs_clock;
}

int v[N<<2];
inline void pushUp(int rt) {
    v[rt] = v[ls] < v[rs]? v[ls] : v[rs];
} 

void build(int rt, int l, int r) {
    if(l == r) {
        v[rt] = a[l];
        return ;
    }
    int mid = (l + r) >> 1;
    build(ls, l, mid);
    build(rs, mid+1, r);
    pushUp(rt);
}

void update(int rt, int l, int r, int a, int b) {
    if(l == r) {
        v[rt] = b;
        return ;
    }
    int mid = (l + r) >> 1;
    if(a <= mid) {
        update(ls, l, mid, a, b);
    }
    else {
        update(rs, mid+1, r, a, b);
    }
    pushUp(rt);
}

int query(int rt, int l, int r, int a, int b) {
    if(a > b) return INT_MAX;
    if(a <= l && r <= b) {
        return v[rt]; 
    }
    int mid = (l + r) >> 1;
    int res = INT_MAX;
    if(a <= mid) {
        res = min(res, query(ls, l, mid, a, b));
    }
    if(b > mid) {
        res = min(res, query(rs, mid+1, r, a, b));
    }
    return res;
}

void initLca(int n) {
    for(int j = 1; j < 20; ++ j) {
        for(int i = 1; i <= n; ++ i) {
            f[i][j] = f[f[i][j-1]][j-1];
        }
    }
}

int go(int x, int d) {
    for(int i = 0; i < 20; ++ i) {
        if(d&(1<<i)) {
            x = f[x][i];
        }
    }
    return x;
}

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    int rt;
    for(int i = 1; i <= n; ++ i) {
        int x;
        scanf("%d%d", &x, &b[i]);
        if(x == 0) rt = i;
        else addEdge(x, i);
    } 
    dfs(rt);
    build(1, 1, n);
    initLca(n);
    while(m --) {
        char op[5];
        scanf("%s", op);
        if(op[0] == 'Q') {
            int x;
            scanf("%d", &x);
            if(x == rt) {
                printf("%d\n", v[1]);
            }
            /*  error
            else if(dep[x] > dep[rt]) {
                int res = query(1, 1, n, l[x], r[x]);
                printf("%d\n", res);
            } 
            */
            else if(l[x] < l[rt] && r[x] >= r[rt]) {
                int di = dep[rt] - dep[x] - 1; 
                int y = go(rt, di);
                int res = query(1, 1, n, 1, l[y]-1);
                res = min(res, query(1, 1, n, r[y]+1, n));
                printf("%d\n", res);
            }
            else {
                int res = query(1, 1, n, l[x], r[x]);
                printf("%d\n", res);
            }
        }
        else if(op[0] == 'V'){
            int x, y;
            scanf("%d%d", &x, &y);
            update(1, 1, n, l[x], y);
        }
        else {
            scanf("%d", &rt);
        }
    }

    return 0;
}

 

  

 

 
posted @ 2017-10-21 13:00  zq216991  阅读(280)  评论(2编辑  收藏  举报