HDU5390 Tree(线段树 + Trie)

/**
题意:一棵N个节点的有根树,一开始每个节点都有一个权值,有m个操作:
1 x : 查询x到根节点的路径上,max{val[x] ^ val[v]},v是x到根节点上路径上的点
0 x y: 将节点x的权值改为y,即val[x] = y

思路:查询x到根节点的路径上的点的影响,可以转换为每次修改一个点给这个点的子树中每个点都影响,这样跑出dfs序列后,修改一个点的影响用线段树维护
就行了,又是查询异或值最大,容易想到trie,然后普通的线段树套trie出来了,查询的时候从最底层的节点往上爬贪心求最大值,更新的时候给节点对应的子
树区间删除原来的值再插入原来的值就可以了,这里插入的时候,不需要延迟标记下传,只要知道每个节点的区间对应线段树的哪些节点就行了,但是这样会超
内存,可以对线段树分层处理,因为插入到某个节点后是不用下传的,那么每次修改一个节点它对应要修改的线段树的节点是一样的,所以可以考虑每次处理
每个节点一层对答案的影响, 处理logn层,这样就不会超内存了
*/

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e5 + 10;
using namespace std;

struct op {
    int t, x, y;
    void input() {
        scanf("%d", &t);
        if(t) scanf("%d", &x);
        else scanf("%d %d", &x, &y);
    }
} rec[maxn];
int T, n, m, kase = 1;
vector<int> G[maxn];
int pre[maxn], val[maxn];
int L[maxn], R[maxn], tot;
int vt[maxn], ans[maxn];

int trie[maxn * 40][2], trie_size;
int trie_val[maxn * 40];
int root[maxn * 8], ival[maxn];

void insert_or_delete(int &rt, int x, int data) {
    if(!rt) {
        trie[trie_size][0] = trie[trie_size][1] = trie_val[trie_size] = 0;
        rt = trie_size++;
    }
    int u = rt;
    for(int i = 29; i >= 0; i--) {
        int k = (x >> i) & 1;
        if(!trie[u][k]) { trie_val[trie_size] = trie[trie_size][0] = trie[trie_size][1] = 0; trie[u][k] = trie_size++; }
        u = trie[u][k]; trie_val[u] += data;
    }
}

int query_max(int u, int x) {
    int res = 0;
    for(int i = 29; i >= 0; i--) {
        int k = (x >> i) & 1;
        if(trie[u][!k] && trie_val[trie[u][!k]]) {  ///相反的数存在 而且没有被删除
            res = res | (1 << i);
            u = trie[u][!k];
        } else {
            u = trie[u][k];
        }
    }
    return res;
}

void dfs(int x, int fa) {
    L[x] = tot; vt[tot++] = x;
    for(int i = 0; i < G[x].size(); i++) {
        int v = G[x][i];
        if(v == fa) continue;
        dfs(v, x);
    }
    R[x] = tot - 1;
}

int seg_pre[maxn * 5], node_cnt, max_dep; ///线段树相关
int ls[maxn * 5], rs[maxn * 5];
int lev[maxn * 5], mp[maxn]; ///每个节点属于线段树中的第几层, 节点在最底层的位置

void build(int o, int l, int r, int lv) {
    lev[o] = lv; max_dep = max(lv, max_dep);
    if(l == r) { mp[vt[l]] = o; return ; }
    int mid = (l + r) >> 1;
    seg_pre[node_cnt] = o; ls[o] = node_cnt;
    build(node_cnt++, l, mid, lv + 1);
    seg_pre[node_cnt] = o; rs[o] = node_cnt;
    build(node_cnt++, mid + 1, r, lv + 1);
}

typedef pair<int, int> pa;
vector<pa> node[maxn];
int it[maxn];
void find_id(int x, int o, int l, int r, int xl, int xr) {
    if(l > xr || r < xl) return ;
    if(l >= xl && r <= xr) { node[x].push_back(pa(lev[o], o)); return ; }
    int mid = (l + r) >> 1;
    find_id(x, ls[o], l, mid, xl, xr);
    find_id(x, rs[o], mid + 1, r, xl, xr);
}

void init_segment_tree() {
    memset(it, 0, sizeof it);
    memset(ans, 0, sizeof ans);
    max_dep = 1; node_cnt = 2;
    build(1, 1, tot - 1, 1);
    for(int i = 0; i < maxn; i++) node[i].clear();
    for(int i = 1; i <= n; i++) {
        find_id(i, 1, 1, tot - 1, L[i], R[i]);
        sort(node[i].begin(), node[i].end());
    }
}

void deal_with(int ce) {  ///处理第ce层线段树的节点
    memset(root, 0, sizeof root);
    trie_size = 1;
    for(int i = 1; i <= n; i++) {
        while(it[i] < node[i].size() && node[i][it[i]].first < ce) it[i]++;
        ival[i] = val[i];
    }
    for(int i = 1; i <= n; i++) { ///初始状态
        for(int x = it[i]; x < node[i].size() && node[i][x].first == ce; x++) {
            insert_or_delete(root[node[i][x].second], val[i], 1);
        }
    }
    for(int i = 1; i <= m; i++) {
        int type = rec[i].t, x = rec[i].x, y = rec[i].y;
        if(type == 0) {  ///修改
            for(int j = it[x]; j < node[x].size() && node[x][j].first == ce; j++) {
                int o = node[x][j].second;
                insert_or_delete(root[o], ival[x], -1);
                insert_or_delete(root[o], y, 1);
            }
            ival[x] = y;
        } else {
            int o = mp[x];
            for( ; lev[o] >= ce; o = seg_pre[o]) {
                if(lev[o] == ce) { ans[i] = max(ans[i], query_max(root[o], ival[x])); }
            }
        }
    }
}

int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d %d", &n, &m); tot = 1; pre[1] = 0;
        for(int i = 0; i < maxn; i++) G[i].clear();
        for(int i = 2; i <= n; i++) {
            scanf("%d", &pre[i]);
            G[pre[i]].push_back(i);
        }
        for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
        dfs(1, 0);
        init_segment_tree();
        for(int i = 1; i <= m; i++) rec[i].input();
        for(int i = 1; i <= max_dep; i++) deal_with(i);
        for(int i = 1; i <= m; i++) if(rec[i].t) printf("%d\n", ans[i]);
    }
    return 0;
}

    原文作者:Trie树
    原文地址: https://blog.csdn.net/hnust_Derker/article/details/79580753
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注