Description
给出一个 n n 个点条边的无向图,任意两点之间至多两条路径,以 flow(s,t) f l o w ( s , t ) 表示 s,t s , t 两点之间的最大流,求 ∑1≤s<t≤ns⊕t⊕flow(s,t) ∑ 1 ≤ s < t ≤ n s ⊕ t ⊕ f l o w ( s , t )
Input
第一行一整数 T T 表示用例组数,每组用例首先输入两个整数表示点数和边数,最后 m m 行每行输入三个整数表示 u,v u , v 之间有一条流量为 w w 的边
Output
输出结果
Sample Input
2
3 3
1 2 5
2 3 6
3 1 5
5 6
1 2 5
2 3 6
3 1 5
3 4 6
4 5 5
5 3 6
Sample Output
27
116
Solution
由于两点之前至多两条路径,显然可知每条边至多属于一个环(否则两个环上的点之间至少有四条路径),两点之间最大流等于最小割,两点之间如果只有一条路径那么必然会割掉这条路径上边权最小值,两点之间如果有两条路径,那么有两种情况,一种是依旧断一条边权最小的边使得两点不可达,一种是断掉环上的两条边使得两点不可达. 同时注意到如果断环上两条边,那么其中一条必然是环上边权最小值,另一条需要根据两点的可达情况来选择,那么我们把每个环上边权最小的边删掉,将其边权加到该环所有剩余边的边权上,将该图变成一棵树,则该树上两点之间的最小割与原图这两点之间的最小割等价. 而求树上两点的最小割,只需类似 Kruskal K r u s k a l ,按边权从大到小加入边,用并查集维护连通分量,当前加入的边 u→v u → v 的边权必然是 u u 所处集合点到所处集合点的最小割,由于结果是要累加编号与最小割的异或和,故每个联通分量里需要维护二进制第 j j 位为的数量,每次根据边权在第 j j 位的值来判断需要两个点集在该位的状态,注意到结果会爆,要用 unsigned long long u n s i g n e d l o n g l o n g
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef unsigned long long ull;
#define maxn 100005
struct Edge
{int u,v,w,flag,next;
}edge[3*maxn];
int tot,head[maxn];
void add(int u,int v,int w)
{edge[tot].u=u,edge[tot].v=v,edge[tot].w=w,edge[tot].flag=0;edge[tot].next=head[u],head[u]=tot++;
}
int T,n,m,vis[maxn],pre[maxn];
vector<int>s,e;
void dfs(int u,int id)
{vis[u]=1;for(int i=head[u];~i;i=edge[i].next){if(edge[i].flag)continue;edge[i].flag=edge[i^1].flag=1;int v=edge[i].v,w=edge[i].w;s.push_back(i);if(vis[v]){int mn=w;for(int i=s.size()-1;i>=0;i--){mn=min(mn,edge[s[i]].w);edge[s[i]].flag=2;//环边 if(edge[s[i]].u==v)break;}int flag=0;while(1){int temp=s.back();s.pop_back();if(!flag&&edge[temp].w==mn)flag=1;else{edge[temp].w+=mn;e.push_back(temp);}if(edge[temp].u==v)break;}continue;}dfs(v,i);}if(id!=-1&&edge[id].flag!=2){e.push_back(s.back());s.pop_back();}
}
bool cmp(int x,int y)
{return edge[x].w>edge[y].w;
}
int fa[maxn],num[maxn][31],Size[maxn];
int find(int x)
{if(fa[x]==x)return x;return fa[x]=find(fa[x]);
}
int main()
{scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);tot=0;memset(head,-1,sizeof(head));while(m--){int u,v,w;scanf("%d%d%d",&u,&v,&w);add(u,v,w),add(v,u,w);}e.clear();memset(vis,0,sizeof(vis));dfs(1,-1);sort(e.begin(),e.end(),cmp);for(int i=1;i<=n;i++){fa[i]=i;Size[i]=1;for(int j=0;j<=30;j++)if((i>>j)&1)num[i][j]=1;else num[i][j]=0;}ull ans=0;for(int i=0;i<e.size();i++){int u=edge[e[i]].u,v=edge[e[i]].v,w=edge[e[i]].w;u=find(u),v=find(v);for(int j=0;j<=30;j++){ull res=0;if((w>>j)&1){res+=(ull)num[u][j]*num[v][j];res+=(ull)(Size[u]-num[u][j])*(Size[v]-num[v][j]);}else{res+=(ull)num[u][j]*(Size[v]-num[v][j]);res+=(ull)(Size[u]-num[u][j])*num[v][j];}ans+=(1ull<<j)*res;}for(int j=0;j<=30;j++)num[v][j]+=num[u][j];fa[u]=v,Size[v]+=Size[u];}printf("%llu\n",ans);}return 0;
}