JZOJ6017. 【GDOI2019模拟2019.2.14】小b爱旅行

Description

在这里插入图片描述

Data Constraint

在这里插入图片描述

Solution

  • 看到异或的种数我呢吧不难想到线性基。
  • 是否能将每一个环独立出来使得它们能够任意组合呢?这样才能满足线性基的性质。
  • 我们先建一棵DFS树,剩下一些返祖边。
  • 每一条返祖边对应一个环。
  • 这些环都是互不影响的。
  • 我们在任意一个点都可以得到正好这个环的贡献并回到原点(只要它们联通)。
  • 于是我们的任意路径就变成了从1出发的一条树链,加上任意的环。
  • 我们需要统计这样有多少种。
  • 将环加入线性基中,如果一条路径的权值的某个位置为1,并且线性基这个位置不为空,就异或一下,最后得到的路径权值就变成了最小表示。也就是说这个时候相同的路径是等价的。
  • 答案就是:不同的路径条数*2^线性基大小。
  • 考虑删边,不妨离线变为加边。
  • 如果加了一条树边,就往下遍历新的子树,因为这些点都是没有遍历过的,所以时间复杂度有保证。
  • 对于每一个新的环,如果更新了线性基就重新计算所有答案,因为线性基只会被更新log次。
  • 最后计算答案。
  • 时间复杂度O(nlogw+nlog2w)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 100005
#define maxm 400005
#define ll long long 
using namespace std;

int n,m,q,i,j,k,tim;
int em,e[maxm],nx[maxm],ls[maxm],bz[maxm],que[maxm];
ll x,y,z,a[maxm][3],ec[maxm],ans[maxm],sum[maxn],p[63],Ans,v[maxn],siz;
int vis[maxm],d[maxm],tot,dep[maxm];

void insert(int x,int y,ll z){
	em++; 
	e[em]=y; 
	nx[em]=ls[x]; 
	ls[x]=em; 
	ec[em]=z;
	em++; e[em]=x; nx[em]=ls[y]; ls[y]=em; ec[em]=z;
}

int add(ll x){
	for(ll i=62;i>=0;i--) if (x>>i){
		if (!(x>>i)) continue;
		if (!p[i]) {p[i]=x;siz++;return 1;}
		x^=p[i];
	}
	return 0;
}

ll view(ll x){
	for(ll i=62;i>=0;i--) if (((x>>i)&1)&&p[i])
		x^=p[i];
	return x;
}

int dfs(int x,int p){
	vis[x]=1; d[++tot]=x; dep[x]=dep[p]+1; 
	int tmp=0;
	for(int i=ls[x];i;i=nx[i]) if (e[i]!=p){
		if (!vis[e[i]]) sum[e[i]]=sum[x]^ec[i],tmp|=dfs(e[i],x);
		else {
			if (dep[e[i]]<dep[x]) tmp|=add(ec[i]^sum[x]^sum[e[i]]);
		}
	}
	return tmp;
}

const ll mo=3000007,c1=17,c2=233;
int hs[mo];
void push_hash(ll x){hs[(x%mo*c1+c2)%mo]=0;}
void add_hash(ll x){
	ll tmp=(x%mo*c1+c2)%mo;
	if (!hs[tmp]) Ans++;
	hs[tmp]=1;
}

void redo(){
	for(i=1;i<=n;i++) if (vis[i]) push_hash(v[i]);
	Ans=0;
	for(i=1;i<=n;i++) if (vis[i]) add_hash(v[d[i]]=view(sum[d[i]]));	
}

int main(){
	freopen("travel.in","r",stdin);
	freopen("travel.out","w",stdout);
	scanf("%d%d%d",&n,&m,&q);
	for(i=1;i<=m;i++) scanf("%lld%lld%lld",&a[i][0],&a[i][1],&a[i][2]);
	for(i=1;i<=q;i++) scanf("%d",&que[i]),bz[que[i]]=1;
	tim=q+1;
	for(i=1;i<=m;i++) if (!bz[i]) insert(a[i][0],a[i][1],a[i][2]);
	sum[1]=0; 
	tot=0; dfs(1,0);
	Ans=0; for(i=1;i<=tot;i++) add_hash(v[d[i]]=view(sum[d[i]]));
	ans[q+1]=Ans*(1ll<<siz);
	
	for(tim=q;tim;tim--){
		x=a[que[tim]][0],y=a[que[tim]][1],z=a[que[tim]][2];
		insert(x,y,z);
		if (vis[x]&&vis[y]) {
			if (add(z^sum[x]^sum[y])) redo();
		} else
		if (vis[x]||vis[y]){
			if (vis[y]) swap(x,y);
			tot=0; int tmp=0;
			sum[y]=sum[x]^z,tmp=dfs(y,x); 
			if (tmp) redo(); else 
			for(i=1;i<=tot;i++) add_hash(v[d[i]]=view(sum[d[i]]));
		} 
		ans[tim]=Ans*(1ll<<siz);
	}
	for(i=1;i<=q+1;i++) printf("%lld\n",ans[i]);
}
posted @ 2019-02-15 22:52  Deep_Thinking  阅读(116)  评论(0编辑  收藏  举报