P6018 [Ynoi2010] Fusion tree

lxl 说过邻域信息维护父亲一定死,所以数据结构维护每个点的儿子,特判父亲。

考虑每个点的数据结构需要支持什么操作:全局加一,单点修改,全局异或和。用 01Trie 维护。

与维护最大异或对的 01Trie 不同,从低位到高位建树,每个点上维护子树异或和,修改时 push up。

考虑怎么 push up。从 u 往其 0/1 子树中走到叶子形成的数,就是从 u0/1 孩子走到叶子形成的数后面加一位 0/1

所以 u 子树数集包含 u0 孩子子树数集中所有数后面加一位 0u1 孩子子树数集中所有数后面加一位 1

u 子树数集中,u0 孩子子树异或和后面加一位 0;若 u1 孩子子树数集大小为奇数,其异或和后面加一位 1,否则加 0

考虑怎么全局加一。加一的过程实际上是从低到高按位取反,若当前位取反后为 0 则继续取反下一位,

所以从上往下交换 0/1 孩子,然后继续交换 0 孩子的 0/1 孩子。

指针非常好写。

#include <cstdio>
#include <algorithm>
#define V(x) a[x] + z[f[x]]
#define O(x, k) if(f[x]) C(V(x), 0, r[f[x]]);a[x] += k;if(f[x]) C(V(x), 0, r[f[x]])
using namespace std;
struct E{int v, t;}e[1000050];
int n, m, c, a[500050], z[500050], f[500050], h[500050];
void A(int u, int v) {e[++c] = {v, h[u]};h[u] = c;}
struct T
{
    T *c[2];int s, w;T() : c{0, 0}, w(0) {}void u()
    {
        if(c[s = w = 0]) s ^= c[0]->s, w ^= c[0]->w << 1;
        if(c[1]) s ^= c[1]->s, w ^= c[1]->w << 1 | c[1]->s; 
    }
}*r[500050];
void C(int x, int d, T *&p)
{
    if(!p) p = new T;if(d >= 20) return void(p->s ^= 1);
    C(x, d + 1, p->c[x >> d & 1]);p->u();
}
void M(T *p) {if(p) swap(p->c[0], p->c[1]), M(p->c[0]), p->u();}
void D(int u)
{
    for(int i = h[u], v;i;i = e[i].t)
        if(!r[v = e[i].v]) C(a[v], 0, r[f[v] = u]), D(v);
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1, u, v;i < n;++i)
        scanf("%d%d", &u, &v), A(u, v), A(v, u);
    for(int i = 1;i <= n;++i) scanf("%d", a + i);D(1);
    for(int i = 0, o, x, v;i < m;++i)
    {
        scanf("%d%d", &o, &x);
        switch(o)
        {
            case 1: ++z[x];M(r[x]);if(f[x]) {O(f[x], 1);}break;
            case 2: scanf("%d", &v);O(x, -v);break;
            case 3: printf("%d\n", (r[x] ? r[x]->w : 0) ^ V(f[x]));break;
        }
    }
    return 0;
}
posted @   Jijidawang  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示