CF938G Shortest Path Queries 题解
异或有很多奇妙的小性质,在这道题里都得到了体现。
注意到异或下求出
现在来考虑动态的情形。维护带删除的线性基是困难的,于是考虑处理动态问题的另一种方式:线段树分治。线段树分治利于解决可撤销的问题。在线性基中删除是困难的,但是在线段树每个节点处撤销恢复原来的线性基是
代码:
#include <bits/stdc++.h>
#define N 200005
#define M 31
using namespace std;
int n, m, q;
int P[M];
void insert(int x) {
for (int i = M - 1; ~i; --i)
if ((x >> i) & 1) {
if (!P[i]) {
P[i] = x;
break;
}
x ^= P[i];
}
}
int query(int x) {
for (int i = M - 1; ~i; --i)
if ((x ^ P[i]) < x) x ^= P[i];
return x;
}
int fa[N], siz[N], dor[N];
int fnd(int x) {
return x == fa[x] ? x : fnd(fa[x]);
}
int gtds(int x) {
return x == fa[x] ? 0 : dor[x] ^ gtds(fa[x]);
}
#define pii pair<int, int>
#define mk make_pair
pii stk[N];
int top;
void mge(int x, int y, int z) {
int sx = fnd(x), sy = fnd(y);
if (sx == sy) {
insert(gtds(x) ^ gtds(y) ^ z);
return;
}
if (siz[sx] > siz[sy]) swap(sx, sy), swap(x, y);
stk[++top] = mk(sx, dor[sx]);
dor[sx] = gtds(x) ^ gtds(y) ^ z;
fa[sx] = sy;
siz[sy] += siz[sx];
}
void del(int t) {
while (top > t) {
pii p = stk[top--];
int x = p.first;
siz[fa[x]] -= siz[x];
fa[x] = x;
dor[x] = p.second;
}
}
struct node {
int x, y, z;
};
struct Node {
int l, r;
vector<node>v;
} e[N << 2];
#define l(i) e[i].l
#define r(i) e[i].r
#define v(i) e[i].v
#define lc (p << 1)
#define rc (lc | 1)
void build(int p, int l, int r) {
l(p) = l, r(p) = r;
if (l == r) return;
int mid = (l + r) >> 1;
build(lc, l, mid);
build(rc, mid + 1, r);
}
void update(int p, int l, int r, node x) {
if (l > r || l > r(p) || l(p) > r) return;
if (l <= l(p) && r(p) <= r) return v(p).push_back(x);
update(lc, l, r, x), update(rc, l, r, x);
}
vector<int>ans;
pii que[N];
void dfs(int p) {
int t = top;
vector<int>vp(M + 5);
for (int i = 0; i < M; i++) vp[i] = P[i];
for (auto i : v(p)) mge(i.x, i.y, i.z);
if (l(p) == r(p)) {
int x = que[l(p)].first, y = que[l(p)].second;
if (x == 0) return;
ans.push_back(query(gtds(x) ^ gtds(y)));
}
else dfs(lc), dfs(rc);
del(t);
for (int i = 0; i < M; i++) P[i] = vp[i];
}
map<pii, int>mp, mv;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
iota(fa + 1, fa + n + 1, 1);
fill(siz + 1, siz + n + 1, 1);
for (int i = 1; i <= m; i++) {
int x, y, z;
cin >> x >> y >> z;
if (x > y) swap(x, y);
mp[mk(x, y)] = 1;
mv[mk(x, y)] = z;
}
cin >> q;
build(1, 1, q);
for (int i = 1; i <= q; i++) {
int o, x, y;
cin >> o >> x >> y;
if (x > y) swap(x, y);
if (o == 1) {
int z;
cin >> z;
mp[mk(x, y)] = i;
mv[mk(x, y)] = z;
}
else if (o == 2) {
update(1, mp[mk(x, y)], i - 1, {x, y, mv[mk(x, y)]});
mv[mk(x, y)] = -1;
}
else que[i] = mk(x, y);
}
for (auto i : mp) {
pii p = i.first;
if (mv[p] != -1) update(1, i.second, q, {p.first, p.second, mv[p]});
}
dfs(1);
for (auto i : ans) cout << i << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律