zoukankan      html  css  js  c++  java
  • HDU6350 Always Online

    Always Online

    给定 (n) 个点 (m) 条边的点仙人掌,求

    [sum_{1 ≤ s < t ≤ n} (s ⊕ t ⊕ mathrm{maxflow}(s, t)) ]

    其中 (⊕) 表示异或。

    (T ≤ 100,n ≤ 10^5,n − 1 ≤ m ≤ 1.5(n − 1),sum n ≤ 10^6)

    题解

    考虑点双缩点。

    我们可以把每个环上最小的那条边断掉,把它的容量加到环的其他边上。显然如果路径要经过这个环,那么最小割会优先考虑这条边。

    然后我们按照容量从大到小枚举每一条边,使用并查集维护连通块。每次加边的时候,这条边一定是它连接的两个连通块之间的最小割。那么直接记录每一个bit上面的01数量就行了。

    还要用unsigned long long……不过ACM赛制还好。

    因为有加法操作,所以要做到230。这个WrongAnswer看得我想把HDU的电脑砸了。

    https://blog.csdn.net/V5ZSQ/article/details/82453394

    CO int N=1e5+10;
    struct edge {int u,v,w,f,next;}e[3*N]; // flag
    int head[N],tot;
    int vis[N],stk[N],top;
    vector<int> nw;
    
    IN bool cmp(int i,int j){
    	return e[i].w>e[j].w;
    }
    IN void link(int u,int v,int w){
    	e[++tot]=(edge){u,v,w,0,head[u]},head[u]=tot;
    }
    void dfs(int u,int ine){
    	vis[u]=1;
    	for(int i=head[u];i;i=e[i].next)if(!e[i].f){
    		e[i].f=e[i^1].f=1;
    		stk[++top]=i;
    		if(!vis[e[i].v]){
    			dfs(e[i].v,i);
    			continue;
    		}
    		int mn=e[i].w;
    		for(int j=top;j>=1;--j){
    			mn=min(mn,e[stk[j]].w);
    			e[stk[j]].f=2; // circle edge
    			if(e[stk[j]].u==e[i].v) break;
    		}
    		bool flag=0; // delete only once
    		while(1){
    			int t=stk[top--];
    			if(!flag and e[t].w==mn) flag=1;
    			else{
    				e[t].w+=mn;
    				nw.push_back(t);
    			}
    			if(e[t].u==e[i].v) break;
    		}
    	}
    	if(ine and e[ine].f!=2) nw.push_back(stk[top--]);
    }
    
    int fa[N],siz[N],num[N][31];
    
    int find(int x){
    	return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    void real_main(){
    	int n=read<int>();
    	fill(head+1,head+n+1,0),tot=1;
    	for(int m=read<int>();m--;){
    		int u=read<int>(),v=read<int>(),w=read<int>();
    		link(u,v,w),link(v,u,w);
    		assert(w<1e9);
    	}
    	fill(vis+1,vis+n+1,0);
    	top=0,nw.clear();
    	dfs(1,0);
    	sort(nw.begin(),nw.end(),cmp);
    	for(int i=1;i<=n;++i){
    		fa[i]=i,siz[i]=1;
    		for(int j=30;j>=0;--j) num[i][j]=i>>j&1;
    	}
    	uint64 ans=0;
    	for(int i=0;i<(int)nw.size();++i){
    		int u=e[nw[i]].u,v=e[nw[i]].v,w=e[nw[i]].w;
    		// cerr<<"e= "<<u<<" "<<v<<" "<<w<<endl;
    		u=find(u),v=find(v);
    		for(int j=30;j>=0;--j){ // edit 1: 30 for operator+
    			uint64 sum=0;
    			if(w>>j&1){
    				sum+=(uint64)num[u][j]*num[v][j];
    				sum+=(uint64)(siz[u]-num[u][j])*(siz[v]-num[v][j]);
    			}
    			else{
    				sum+=(uint64)num[u][j]*(siz[v]-num[v][j]);
    				sum+=(uint64)(siz[u]-num[u][j])*num[v][j];
    			}
    			ans+=sum<<j;
    		}
    		for(int j=30;j>=0;--j) num[u][j]+=num[v][j];
    		fa[v]=u,siz[u]+=siz[v];
    	}
    	printf("%llu
    ",ans);
    }
    int main(){
    	for(int T=read<int>();T--;) real_main();
    	return 0;
    }
    
  • 相关阅读:
    PostgreSQL的德哥教程
    pgbench的使用简介
    pg生成日期序列
    在Intellij IDEA 12中Tomcat无法调试
    如何使用命令行来控制IIS服务的启动和停止
    SharePoint Support Engineer 常用技术点
    测试博文写作
    C#数字进制间与字符串类型相互转换
    [转载]INNO Setup 使用笔记
    unity3d 游戏开发引擎
  • 原文地址:https://www.cnblogs.com/autoint/p/12203070.html
Copyright © 2011-2022 走看看