P6018 [Ynoi2010] Fusion tree
操作与一个点相邻的所有点,考虑以
考虑我们要做什么操作?单点修改,全局 pushup
时直接合并左右两子树的点数量。同时维护
void pushup(int u)
{
tr[u].sum = tr[u].cnt = 0;
if (tr[u].son[0])
{
tr[u].cnt += tr[tr[u].son[0]].cnt;
tr[u].sum = tr[tr[u].son[0]].sum << 1;
}
if (tr[u].son[1])
{
tr[u].cnt += tr[tr[u].son[1]].cnt;
tr[u].sum ^= (tr[tr[u].son[1]].sum << 1) | (tr[tr[u].son[1]].cnt & 1);
}
}
其中左移
全局异或即根节点的
现在考虑全局
其实就是从根节点开始,每次尝试往
于是整个题就做完了,特别注意处理父亲节点的贡献。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
using namespace std;
const int N = 5e5 + 5, M = 21;
int rt[N];
int fa[N];
vector<int> son[N];
vector<int> G[N];
int n, m;
int a[N];
int cnt[N], c2[N];
void dfs(int u, int f)
{
fa[u] = f;
for (auto& j : G[u])
{
if (j != f)
{
dfs(j, u);
son[u].emplace_back(j);
}
}
}
inline int qry(int u)
{
int res = a[u] + c2[u] + (fa[u] ? cnt[fa[u]] : 0);
return res;
}
class Trie
{
public:
int idx;
struct Node
{
int cnt, sum;
int son[2];
}tr[2 * N * M];
void pushup(int u)
{
tr[u].sum = tr[u].cnt = 0;
if (tr[u].son[0])
{
tr[u].cnt += tr[tr[u].son[0]].cnt;
tr[u].sum = tr[tr[u].son[0]].sum << 1;
}
if (tr[u].son[1])
{
tr[u].cnt += tr[tr[u].son[1]].cnt;
tr[u].sum ^= (tr[tr[u].son[1]].sum << 1) | (tr[tr[u].son[1]].cnt & 1);
}
}
void ins(int& rt, int x)
{
if (!rt) rt = ++idx;
int u = rt;
vector<int> v;
for (int i = 0; i <= 20; i++)
{
v.emplace_back(u);
int p = ((x >> i) & 1);
if (!tr[u].son[p]) tr[u].son[p] = ++idx;
u = tr[u].son[p];
}
tr[u].cnt++;
for (int i = v.size() - 1; i >= 0; i--) pushup(v[i]);
}
void del(int& rt, int x)
{
int u = rt;
vector<int> v;
for (int i = 0; i <= 20; i++)
{
v.emplace_back(u);
int p = ((x >> i) & 1);
u = tr[u].son[p];
}
tr[u].cnt--;
for (int i = v.size() - 1; i >= 0; i--) pushup(v[i]);
}
void add(int u)
{
swap(tr[u].son[0], tr[u].son[1]);
if (tr[u].son[0]) add(tr[u].son[0]);
pushup(u);
}
}tr;
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
for (int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
G[u].emplace_back(v);
G[v].emplace_back(u);
}
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
dfs(1, 0);
for (int i = 1; i <= n; i++)
{
for (auto& j : son[i]) tr.ins(rt[i], a[j]);
}
while (m--)
{
int op;
cin >> op;
if (op == 1)
{
int u;
cin >> u;
tr.add(rt[u]);
int rm = qry(fa[u]);
cnt[u]++;
if (fa[u]) c2[fa[u]]++;
if (fa[fa[u]])
{
tr.del(rt[fa[fa[u]]], rm);
tr.ins(rt[fa[fa[u]]], rm + 1);
}
}
else if (op == 2)
{
int u, x;
cin >> u >> x;
int rm = qry(u);
if (fa[u])
{
tr.del(rt[fa[u]], rm);
tr.ins(rt[fa[u]], rm - x);
}
a[u] -= x;
}
else if (op == 3)
{
int u;
cin >> u;
int res = (fa[u] ? qry(fa[u]) : 0);
res ^= tr.tr[rt[u]].sum;
cout << res << "\n";
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现