【题目】
BZOJ
n
n
n个点
m
m
m条边的无向图,边有边权,有
Q
Q
Q次删边操作,每次操作后询问从
1
1
1号点出发有多少种不同的路径异或和,路径可以重复经过。
n
,
m
,
Q
≤
2
×
10
n,m,Q\leq 2\times 10%^5,w_i\leq 10^{18}
n,m,Q≤2×10
(原题数据更小一点qwq,实际上答案应该是
O
(
W
n
)
O(Wn)
O(Wn)级别的,不过可以出这么大就是了。)
【解题思路】
首先考虑
Q
=
0
Q=0
Q=0的情况并假设图连通。
不妨求出图的一棵生成树,定义非树边对应的环为一条非树边和其端点在树上的路径之并。不难发现从
1
1
1开始任意路径的异或值等价于从
1
1
1开始的一条树链异或上一些非树边对应的环。
于是我们求出所有非树边对应环的线性基,对于每条从 1 1 1开始的树链权,我们在线性基上跑一遍,使得权值能变成 0 0 0的位全部变成 0 0 0。记录下有几个不同的结果(不妨使用 set \text{set} set),那么答案即再乘上 2 线 性 基 大 小 2^{线性基大小} 2线性基大小。
对于 Q > 0 Q>0 Q>0,由于线性基(一般)不支持删除,不妨倒序将删除变为加入,此时分情况讨论。
- 若加入边两个端点均不在 1 1 1连通块中,则对答案(暂时)无影响,先不管
- 若加入边两个端点均在 1 1 1连通块中,则我们加入了一条非树边,那么我们需要在线性基中插入它对应的环的权值,然后将所有的从 1 1 1出发的树链再跑一次计算答案。由于线性基的性质,一共只会插入 log W ) \log W) logW)次,显然是可行的。
- 若加入边一个端点在 1 1 1连通块中,另一个不在,则我们需要计算新连通块带来的树链和非树边,我们仅需要从新增边开始将这个新连通块进行 DFS \text{DFS} DFS即可。然后再插入环即计算链。
复杂度 O ( n log 2 W + ( m + Q ) α ( n ) ) O(n\log ^2 W+(m+Q)\alpha(n)) O(nlog2W+(m+Q)α(n))。
我已经不会线性基了。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10,M=63;
int tot,n,m,Q;
int head[N],fa[N],qr[N];
bool fg,ban[N],vis[N];
ll dis[N],fc[M];
vector<ll>ans,vec;
set<ll>st;
ll read()
{
ll ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
void write(ll x){if(x>9)write(x/10);putchar(x%10^48);}
void writeln(ll x){write(x);putchar('\n');}
struct Linear_Basis
{
ll A[M];int sz;//error because int A
bool insert(ll x)
{
for(int i=M-1;~i;--i) if(x&fc[i])
{
if(!A[i]) {A[i]=x;++sz;return 1;}
else x^=A[i];
}
return 0;
}
ll query(ll x)
{
for(int i=M-1;~i;--i) if((x&fc[i]) && A[i]) x^=A[i];
return x;
}
}B;
struct Tway{ll w;int v,nex;}e[N<<1];
void add(int u,int v,ll w)
{
e[++tot]=(Tway){w,v,head[u]};head[u]=tot;
e[++tot]=(Tway){w,u,head[v]};head[v]=tot;
}
void dfs(int x)
{
vis[x]=1;ll res=B.query(dis[x]);
if(res) st.insert(res);
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
if(v==fa[x] || ban[i>>1]) continue;
if(!vis[v]) fa[v]=x,dis[v]=dis[x]^e[i].w,dfs(v);
else if(B.insert(dis[v]^dis[x]^e[i].w)) fg=1;
}
}
void update()
{
if(!fg) return;vec.clear();
for(set<ll>::iterator it=st.begin();it!=st.end();++it) vec.push_back(*it);
st.clear();ll x;//error because int x
for(int i=0;i<(int)vec.size();++i)
if((x=B.query(vec[i]))) st.insert(x);
}
void rebuild(int k)
{
int u=e[k<<1].v,v=e[k<<1|1].v;ll w=e[k<<1].w;
ban[k]=fg=0;
if(!vis[u] && !vis[v]) return;
else if(!vis[u]) fa[u]=v,dis[u]=dis[v]^w,dfs(u);
else if(!vis[v]) fa[v]=u,dis[v]=dis[u]^w,dfs(v);
else if(B.insert(dis[v]^dis[u]^w)) fg=1;
update();
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ2322.in","r",stdin);
freopen("BZOJ2322.out","w",stdout);
#endif
fc[0]=1;for(int i=1;i<M;++i)fc[i]=fc[i-1]<<1;tot=1;
n=read();m=read();Q=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();ll w=read();
add(u,v,w);
}
for(int i=1;i<=Q;++i) ban[qr[i]=read()]=1;
ans.resize(Q+1);
dfs(1);update();ans[Q]=1ll*(st.size()+1)*fc[B.sz]-1;
for(int i=Q;i;--i) rebuild(qr[i]),ans[i-1]=1ll*(st.size()+1)*fc[B.sz]-1;
for(int i=0;i<=Q;++i) writeln(ans[i]);
return 0;
}