题面
解题思路
先不考虑删边,我们能够观察到如下重要的性质:
1.做出图的生成树,则任意一条路径可以由生成树的上路径异或上若干环组成。
2.一条路径可以并上任何一个环,即使不相邻。 因为我们可以直接走到那个环,走一圈然后原路返回。因为异或性质,中间路径被消除了。
我们可以将环的权值扔进线性基里,1到任何一点的距离去和线性基求答案。我们可以用线性基将一个距离削成最小表示。如果两个距离的最小表示相同,则他们通过线性基构成的东西也相同。
则答案是 距离的最小表示不同的个数 * 2^(线性基的大小)。
考虑删边,我们倒着做,就是加边。
我们将和1不相邻的连通块和环存起来,在连接时加入。
如果线性基改变,那么最小表示也将改变,因此我们要重构最小表示。由于线性基至多改变60次,复杂度是合法的。
复杂度
O
(
60
n
l
o
g
2
n
)
O(60nlog_2n)
O(60nlog2n)
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
using namespace std;
#define MP make_pair
typedef long long ll;
template <class T>
void read(T &x) {
x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
}
void write(ll x) {
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
const int N = 2e5 + 100;
const int M = 65;
ll p[M], sz;
bool insert(ll x) {
for (int i = 60; i >= 0; i--) {
if (x & (1LL << i)) {
if (p[i]) x ^= p[i];
else {
p[i] = x;
sz++;
return true;
}
}
}
return false;
}
ll fun(ll x) {
for (int i = 60; i >= 0; i--)
if ((x & (1LL << i)) && p[i]) x ^= p[i];
return x;
}
int fa[N];
int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
bool join(int x, int y) {
x = find(x); y = find(y);
if (x == y) return false;
fa[x] = y;
return true;
}
int n, m, q;
int uu[N], vv[N], id[N], has[N];
bool vis[N];
ll ww[N], dis[N], ans[N];
vector<pair<int, ll> > V[N];
vector<int> R[N];
set<ll> S;
void dfs(int u, int fa) {
S.insert(fun(dis[u]));
for (auto x : V[u]) {
ll v = x.first, w = x.second;
if (v == fa) continue;
dis[v] = dis[u] ^ w;
dfs(v, u);
}
}
void build() {
set<ll> s;
for (auto it = S.begin(); it != S.end(); it++) s.insert(fun(*it));
swap(s, S);
}
int main() {
//freopen("0.txt", "r", stdin);
read(n); read(m); read(q);
for (int i = 1; i <= m; i++) read(uu[i]), read(vv[i]), read(ww[i]);
for (int i = 1; i <= q; i++) read(id[i]), vis[id[i]] = true;
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= m; i++) {
if (vis[i]) continue;
if (join(uu[i], vv[i])) {
V[uu[i]].push_back(MP(vv[i], ww[i]));
V[vv[i]].push_back(MP(uu[i], ww[i]));
}
}
S.insert(0);
dfs(1, 0);
for (int i = 1; i <= m; i++) {
if (vis[i]) continue;
if (find(uu[i]) == find(1)) insert(dis[uu[i]] ^ dis[vv[i]] ^ ww[i]);
else R[find(uu[i])].push_back(i);
}
build();
ans[q + 1] = (1LL << sz) * S.size();
for (int i = q; i >= 1; i--) {
ll u = uu[id[i]], v = vv[id[i]], w = ww[id[i]];
if (find(u) == find(v)) {
if (find(u) == find(1)) {
if (insert(dis[u] ^ dis[v] ^ w)) build();
}
else R[find(u)].push_back(id[i]);
}
else {
if (find(u) == find(1) || find(v) == find(1)) {
if (find(v) == find(1)) swap(u, v);
dis[v] = dis[u] ^ w;
V[u].push_back(MP(v, w));
dfs(v, u);
bool flag = false;
for (int i : R[find(v)]) {
if (insert(dis[uu[i]] ^ dis[vv[i]] ^ ww[i])) flag = true;
}
if (flag) build();
join(u, v);
}
else {
V[u].push_back(MP(v, w));
V[v].push_back(MP(u, w));
u = find(u); v = find(v);
if (R[u].size() > R[v].size()) swap(u, v);
for (int x : R[u]) R[v].push_back(x);
join(u, v);
}
}
ans[i] = (1LL << sz) * S.size();
}
for (int i = 1; i <= q + 1; i++) write(ans[i]), puts("");
return 0;
}