由于原图是仙人掌,可以将一个简单环中流量最小的边删掉,并让该环中剩下的边加上该边的流量,最终形成一棵树。类似于瓶颈树,将边按流量排序,按流量从大到小的顺序加入。将异或的贡献拆位,维护每个连通块每个二进制位为 0 0 0和 1 1 1的点个数即可计算答案。
#include<stdio.h>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
#define R register int
#define I inline
#define N 100001
#define INF 2000001
struct Edge{
int End,Cap;
};
I Edge Pair(int x,int y){
Edge res;
res.End=x;
res.Cap=y;
return res;
}
vector<Edge>G[N];
int dep[N],f[N],c[N],ctb[N][21][2];
I void Tarjan(int x,int F,set<pair<int,int> >&E,map<pair<int,int>,int>&A){
dep[x]=dep[F]+1;
f[x]=F;
int v;
for(vector<Edge>::iterator T=G[x].begin();T!=G[x].end();T++){
v=T->End;
if(dep[v]==0){
c[v]=T->Cap;
Tarjan(v,x,E,A);
}else if(v!=F&&dep[v]<dep[x]){
int minC=INF,minI;
for(R i=x;i!=v;i=f[i]){
if(c[i]<minC){
minC=c[i];
minI=i;
}
}
if(T->Cap<minC){
E.insert(make_pair(x,v));
E.insert(make_pair(v,x));
minI=0;
minC=T->Cap;
}else{
E.insert(make_pair(minI,f[minI]));
E.insert(make_pair(f[minI],minI));
A[make_pair(x,v)]=A[make_pair(v,x)]=minC;
}
for(R i=x;i!=v;i=f[i]){
if(i!=minI){
A[make_pair(i,f[i])]=A[make_pair(f[i],i)]=minC;
}
}
}
}
}
struct Link{
int Start,End,Cap;
I friend bool operator<(Link A,Link B){
return A.Cap>B.Cap;
}
};
I int GetF(int x){
if(x==f[x]){
return x;
}
f[x]=GetF(f[x]);
return f[x];
}
int main(){
int n,m,x,y,z;
scanf("%d%d",&n,&m);
for(R i=m;i!=0;i--){
scanf("%d%d%d",&x,&y,&z);
G[x].push_back(Pair(y,z));
G[y].push_back(Pair(x,z));
}
set<pair<int,int> >E;
map<pair<int,int>,int>A;
Tarjan(1,0,E,A);
for(R i=1;i<=n;i++){
for(R j=0;j!=G[i].size();j++){
if(E.count(make_pair(i,G[i][j].End))!=0){
G[i][j]=G[i].back();
G[i].pop_back();
j--;
}else if(A.count(make_pair(i,G[i][j].End))!=0){
G[i][j].Cap+=A[make_pair(i,G[i][j].End)];
}
}
}
vector<Link>B;
for(R i=1;i<=n;i++){
Link Tem;
Tem.Start=i;
for(vector<Edge>::iterator T=G[i].begin();T!=G[i].end();T++){
y=T->End;
if(i<y){
Tem.End=y;
Tem.Cap=T->Cap;
B.push_back(Tem);
}
}
f[i]=i;
for(R j=0;j!=21;j++){
ctb[i][j][i>>j&1]++;
}
}
sort(B.begin(),B.end());
long long ans=0;
for(vector<Link>::iterator T=B.begin();T!=B.end();T++){
x=GetF(T->Start);
y=GetF(T->End);
z=T->Cap;
for(R j=0;j!=21;j++){
for(R k=0;k!=2;k++){
ans+=(long long)ctb[x][j][k]*ctb[y][j][z>>j&1^1^k]<<j;
}
}
for(R j=0;j!=21;j++){
ctb[y][j][0]+=ctb[x][j][0];
ctb[y][j][1]+=ctb[x][j][1];
}
f[x]=y;
}
printf("%lld",ans);
return 0;
}