困难分治题
怎么没人写题解,我来写一发!
题意
有一个无向连通图,每条边有权值
题解
先考虑路径异或的转化。这是一个经典问题:先加入
实现时维护两个独立并查集:
把所有边离线做时间轴分治,叶子从左到右处理,处理到叶子时前一条边已经解密。
考虑区间
第一轮:把编号在
第二轮:在已加入
令
叶子
复杂度:设当前区间未来边数为
#include <bits/stdc++.h>
using namespace std;
const int N = 4e5 + 10;
struct Dsu1{
int f[N], sz[N];
stack<pair<int, int> > stk;
void init(int n) {for (int i = 1; i <= n; i++) f[i] = i, sz[i] = 1;}
int find(int u) {while (f[u] != u) u = f[u]; return u;}
bool merge(int u, int v) {
u = find(u), v = find(v);
if (u == v) return 0;
if (sz[u] < sz[v]) swap(u, v);
stk.push({u, v});
f[v] = u;
sz[u] += sz[v];
return 1;
}
void pop(int x) {
while ((int)stk.size() > x) {
auto [u, v] = stk.top();
sz[u] -= sz[v];
f[v] = v;
stk.pop();
}
}
}D1;
struct Bs{
int bs[31];
stack<int> stk;
void insert(int x) {
for (int i = 30; i >= 0; i--) {
if (!((x >> i) & 1)) continue;
if (!bs[i]) {stk.push(i); bs[i] = x; return ;};
x ^= bs[i];
}
}
int query() {
int res = 0;
for (int i = 30; i >= 0; i--) res = max(res, res ^ bs[i]);
return res;
}
void pop(int x) {
while ((int)stk.size() > x) {
bs[stk.top()] = 0;
stk.pop();
}
}
};
struct Dsu2{
int f[N], sz[N], w[N];
Bs b;
stack<tuple<int, int, int> > stk;
void init(int n) {for (int i = 1; i <= n; i++) f[i] = i, sz[i] = 1, w[i] = 0;}
int find(int u, int &res) {while (f[u] != u) res ^= w[u], u = f[u]; return u;}
bool merge(int u, int v, int c) {
int resu = 0, resv = 0;
u = find(u, resu), v = find(v, resv);
if (u == v) {
stk.push({-1, -1, (int)b.stk.size()});
b.insert(resu ^ resv ^ c);
return 0;
}
if (sz[u] < sz[v]) swap(u, v), swap(resu, resv);
stk.push({u, v, resv});
f[v] = u;
sz[u] += sz[v];
w[v] = resu ^ resv ^ c;
return 1;
}
void pop(int x) {
while ((int)stk.size() > x) {
auto [u, v, resv] = stk.top();
stk.pop();
if (u == -1) {
b.pop(resv);
continue;
}
sz[u] -= sz[v];
f[v] = v;
w[v] = resv;
}
}
}D2;
struct Edge{
int u, v, w, c;
void decode(int x) {
int a = (1ll * x * 987654321 + 123456789) % (1 << 30);
w ^= a, c ^= a;
}
}E[N];
int n, m, k, q;
void solve(int l, int r, vector<int>& chs) {
sort(chs.begin(), chs.end(), [&](int a, int b) {
if (E[a].w != E[b].w) return E[a].w < E[b].w;
else return a < b;
});
pair<int, int> t1 = {D1.stk.size(), D2.stk.size()};
if (l == r) {
for (auto i : chs) if (D1.merge(E[i].u, E[i].v)) {
D2.merge(E[i].u, E[i].v, E[i].c);
}
int ans = D2.b.query();
cout << ans << '\n';
if (l < m + q) E[l + 1].decode(ans);
} else {
for (int i = l + 1; i <= r; i++) D1.merge(E[i].u, E[i].v);
vector<int> must, other;
for (auto i : chs) {
if (D1.merge(E[i].u, E[i].v)) must.push_back(i);
else other.push_back(i);
}
D1.pop(t1.first), D2.pop(t1.second);
for (auto i : must) D1.merge(E[i].u, E[i].v), D2.merge(E[i].u, E[i].v, E[i].c);
pair<int, int> t2 = {D1.stk.size(), D2.stk.size()};
vector<int> pd;
for (auto i : other) if (D1.merge(E[i].u, E[i].v)) pd.push_back(i);
D1.pop(t2.first), D2.pop(t2.second);
int mid = (l + r) / 2;
solve(l, mid, pd);
for (int i = l + 1; i <= mid + 1; i++) pd.push_back(i);
solve(mid + 1, r, pd);
}
D1.pop(t1.first), D2.pop(t1.second);
}
signed main() {
ios :: sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> k;
for (int i = 1; i <= m; i++) {
cin >> E[i].u >> E[i].v >> E[i].w >> E[i].c;
}
D1.init(n), D2.init(n);
for (int i = 1; i <= k; i++) {
int u, v;
cin >> u >> v;
D2.merge(u, v, 0);
}
cin >> q;
for (int i = 1; i <= q; i++) {
cin >> E[m + i].u >> E[m + i].v >> E[m + i].w >> E[m + i].c;
}
vector<int> chs;
for (int i = 1; i <= m; i++) chs.push_back(i);
solve(m, m + q, chs);
return 0;
}