【Ynoi2010】Fusion tree

题目描述
魔法森林里有一颗大树,下面经常有小孩召开法。

大树可以看做一个有 n n n 个节点, n − 1 n - 1 n1 条边的无向连通图。大树的每个节点都有若干瓶矿泉水,初始第 i i i 个节点有 a i a_i ai 瓶矿泉水。

麦杰斯住在大树顶端,有一天他想改造一下大树,方便他巨大多喝水之后可以垃圾分类矿泉水瓶。

麦杰斯喜欢二进制运算,所以他会有以下三种操作:

  1. 将树上与一个节点 x x x 距离为 1 1 1 的节点上的矿泉水数量 + 1 +1 +1。这里树上两点间的距离定义为从一点出发到另外一点的最短路径上边的条数。
  2. 在一个节点 x x x 上喝掉 v v v 瓶水。
  3. 询问树上与一个节点 x x x 距离为 1 1 1 的所有节点上的矿泉水数量的异或和。

麦杰斯共有 m m m 次操作,他希望你在每次 3 3 3 操作后告诉他答案。

输入格式
第一行两个正整数 n , m n,m n,m ,分别表示树的节点个数和麦杰斯的询问个数。

第二行到第 n n n 行,每行两个整数表示有一条连接这两个节点的边。

n + 1 n + 1 n+1 n n n 个整数,第 i i i 个整数表示初始第 i i i 个节点上的矿泉水数量。

n + 2 n + 2 n+2 行到第 n + m + 1 n + m + 1 n+m+1 行,每行先读入一个整数 o p t opt opt 表示操作类型。

如果 o p t = 1 opt = 1 opt=1 3 3 3 ,接下来读入一个整数 x x x 表示麦杰斯操作的节点标号。

否则接下来读入两个整数 x , v x, v x,v 表示麦杰斯操作的节点标号和他喝的水的数量。

输出格式
对于每一个 3 3 3 操作,输出一行一个整数表示答案。

输入输出样例

输入 #1
3 2
1 2
2 3
1 1 4
1 1
3 2
输出 #1
5

说明/提示
Idea:dangxingyu,Solution:dangxingyu,Code:dangxingyu,Data:dangxingyu

对于 30 % 30\% 30% 的数据,满足 n ≤ 1 0 3 n \le 10^3 n103 m ≤ 1 0 3 m\le 10^3 m103

对于 60 % 60\% 60% 的数据,满足 n ≤ 1 0 5 n \le 10^5 n105 m ≤ 1 0 5 m \le 10^5 m105

对于另外 10 % 10\% 10% 的数据,存在一个点满足所有点到该节点的距离 ≤ 1 \le 1 1

对于 100 % 100\% 100% 的数据,满足 1 ≤ n ≤ 5 × 1 0 5 1\le n \le 5\times 10^5 1n5×105 1 ≤ m ≤ 5 × 1 0 5 1\le m \le 5\times 10^5 1m5×105 0 ≤ a i ≤ 1 0 5 0\le a_i \le 10^5 0ai105 1 ≤ x ≤ n 1 \le x \le n 1xn o p t ∈ { 1 , 2 , 3 } opt\in\{1,2,3\} opt{1,2,3}

保证任意时刻每个节点的矿泉水数非负。

使用 01 − t r i e 01-trie 01trie维护每个节点的所有子节点的异或和。
f a [ x ] fa[x] fa[x]表示节点 x x x的父节点; l z y [ x ] lzy[x] lzy[x]表示节点 x x x操作 1 1 1进行的次数; v [ x ] v[x] v[x]表示除去 f a [ x ] fa[x] fa[x]通过操作 1 1 1 x x x进行修改外 x x x的当前值。

  • o p t = 1 opt=1 opt=1时 , l z y [ x ] lzy[x] lzy[x] 1 1 1 v [ f a [ x ] ] v[fa[x]] v[fa[x]] 1 1 1;维护节点 f a [ f a [ x ] ] fa[fa[x]] fa[fa[x]] x x x t r i e trie trie
  • o p t = 2 opt=2 opt=2时, v [ x ] v[x] v[x] v v v;维护节点 f a [ x ] fa[x] fa[x] t r i e trie trie
  • o p t = 2 opt=2 opt=2时,输出 ( v [ f a [ x ] ] + l z y [ f a [ f a [ x ] ] ) ⊕ x 子 节 点 的 异 或 和 (v[fa[x]]+lzy[fa[fa[x]]) \oplus x子节点的异或和 (v[fa[x]]+lzy[fa[fa[x]])x
#include

#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define sc(a) scahf("%c",&a);
#define ss(a) scanf("%s",a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%lld\n",a)
#define pc(a) putchar(a)
#define ms(a) memset(a,0,sizeof(a))
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define repd(i, a, b) for(register int i=a;i>=b;--i)
#define reps(s) for(register int i=head[s];i;i=Next[i])
#define ll long long
#define ull unsigned long long
#define vi vector
#define pii pair
#define mii unordered_map
#define msi unordered_map
#define lowbit(x) ((x)&(-(x)))
#define ce(i, r) i==r?'\n':' '
#define pb push_back
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define INF 0x3f3f3f3f
#define pr(x) cout<<#x<<": "<<x<<endl
using namespace std;

inline int qr() {
    int f = 0, fu = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')fu = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        f = (f << 3) + (f << 1) + c - 48;
        c = getchar();
    }
    return f * fu;
}

const int N = 5e5 + 10;

struct Trie {
    const int H = 18;
    int ch[N * 25][2], w[N * 25], xorv[N * 25], rt[N];
    int tot = 0;

    inline int build() {
        ++tot;
        ch[tot][0] = ch[tot][1] = w[tot] = xorv[tot] = 0;
        return tot;
    }

    inline void update(int p) {
        w[p] = xorv[p] = 0;
        if (ch[p][0]) {
            w[p] += w[ch[p][0]];
            xorv[p] ^= xorv[ch[p][0]] << 1;
        }
        if (ch[p][1]) {
            w[p] += w[ch[p][1]];
            xorv[p] ^= (xorv[ch[p][1]] << 1) | w[ch[p][1]];
        }
        w[p] &= 1;
    }

    void insert(int &p, int d, int x) {
        if (!p)p = build();
        if (d > H) {
            w[p]++;
            return;
        }
        insert(ch[p][x & 1], d + 1, x >> 1);
        update(p);
    }

    void erase(int p, int d, int x) {
        if (d > H) {
            w[p]--;
            return;
        }
        erase(ch[p][x & 1], d + 1, x >> 1);
        update(p);
    }

    void addall(int p) {
        swap(ch[p][0], ch[p][1]);
        if (ch[p][0])addall(ch[p][0]);
        update(p);
    }

    int merge(int p, int q) {
        if (!p)return q;
        if (!q)return p;
        w[p] = w[p] + w[q] & 1, xorv[p] ^= xorv[q];
        ch[p][0] = merge(ch[p][0], ch[q][0]);
        ch[p][1] = merge(ch[p][1], ch[q][1]);
        return p;
    }

} tr;

int head[N], ver[N << 1], Next[N << 1], tot;
int fa[N], v[N], lzy[N], n, m;

inline void add(int x, int y) {
    ver[++tot] = y;
    Next[tot] = head[x];
    head[x] = tot;
}

inline int get(int x) {
    return v[x] + lzy[fa[x]];
}

void dfs(int x, int f) {
    fa[x] = f;
    reps(x) {
        int y = ver[i];
        if (y == f)continue;
        dfs(y, x);
    }
}

int main() {
    n = qr(), m = qr();
    repi(i, 1, n - 1) {
        int x = qr(), y = qr();
        add(x, y), add(y, x);
    }
    dfs(1, 0);
    repi(i, 1, n) {
        v[i] = qr();
        if (fa[i])tr.insert(tr.rt[fa[i]], 0, v[i]);
    }
    while (m--) {
        int op = qr(), x = qr();
        if (op == 1) {
            lzy[x]++;
            if (fa[fa[x]])tr.erase(tr.rt[fa[fa[x]]], 0, get(fa[x]));
            if (fa[x])v[fa[x]]++;
            if (fa[fa[x]])tr.insert(tr.rt[fa[fa[x]]], 0, get(fa[x]));
            tr.addall(tr.rt[x]);
        } else if (op == 2) {
            if (fa[x])tr.erase(tr.rt[fa[x]], 0, get(x));
            v[x] -= qr();
            if (fa[x])tr.insert(tr.rt[fa[x]], 0, get(x));
        } else
            pi(tr.xorv[tr.rt[x]] ^ get(fa[x]));
    }
    return 0;
}

你可能感兴趣的:(trie树,ACM)