做本题前应看看BZOJ2115,同年WC的一道题。
几点启发:
一条路径可以用一条简单路和一些环拼凑而成。
线性基可以随时更新,也就是说我们可以做到动态版本的线性基。
对于一组特定的线性基,任意一个数都有唯一的最小表示。这可以帮助我们找到本质不同的量。
做法可以参见POPOQQQ的博客
代码可以精简如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5100;
typedef long long ll;
struct edge{ int t; ll v; edge(int t=0 , ll v=0):t(t),v(v){} };
int n , m , q;
int x[maxn*10] , y[maxn*10] , a[maxn*10] , book[maxn*10]; ll v[maxn*10];
int p[maxn]; ll key[maxn];
vector<edge> g[maxn];
set<ll> s;
vector<ll> base;
void gauss(ll v)
{
for(int i=0;i<base.size();i++) v = min(v , v^base[i]);
if(!v) return;
base.push_back(v);
sort(base.begin() , base.end()); reverse(base.begin() , base.end());
set<ll> ne;
for(set<ll>::iterator i = s.begin(); i!= s.end() ; ++i) ne.insert(min(*i , *i ^ v));
s = ne;
}
void dfs(int x , int fa , ll v)
{
p[x] = 1;
key[x] = v;
for(int i=0;i<base.size();i++) v = min(v , v^base[i]);
s.insert(v);
for(int i=0;i<g[x].size();i++)
{
edge& e = g[x][i];
if(!p[e.t]) dfs(e.t , x , key[x] ^ e.v);
else gauss(key[e.t] ^ key[x] ^ e.v);
}
}
void add(int x , int y , ll v)
{
g[x].push_back(edge(y , v));
g[y].push_back(edge(x , v));
if(p[x] && p[y]) gauss(key[x] ^ key[y] ^ v);
else if(p[x]) dfs(y , x , key[x]^v);
else if(p[y]) dfs(x , y , key[y]^v);
}
ll res[21000];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
#endif
cin>>n>>m>>q;
for(int i=1;i<=m;i++) scanf("%d%d%lld" , x+i , y+i , v+i);
for(int i=1;i<=q;i++) scanf("%d" , a+i) , book[a[i]] = 1;
p[1] = 1; key[1] = 0; s.insert(0);
for(int i=1;i<=m;i++) if(!book[i]) add(x[i] , y[i] , v[i]);
for(int i=q;i>=0;i--)
{
res[i] = (1LL<<base.size()) * s.size() - 1;
if(i) add(x[a[i]] , y[a[i]] , v[a[i]]);
}
for(int i=0;i<=q;i++) printf("%lld\n" , res[i]);
return 0;
}