zoukankan      html  css  js  c++  java
  • 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
    ",ans[i]);
    }
    
  • 相关阅读:
    java微信小程序调用支付接口
    Java开发中的23种设计模式详解(转)
    SSM框架-SpringMVC 实例文件上传下载
    设计模式--观察者模式
    设计模式之策略模式
    网络通讯简单了解
    android 五子棋开发
    android studio里的build.gradle基本属性
    android studio 真机调试
    java线程知识点
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/11700951.html
Copyright © 2011-2022 走看看