hdu 6350 Always Online 图论并查集

Problem Description
Wayne is an administrator of some metropolitan area network. The network he managed can be formed into a simple connected graph with n vertices and m edges, which means the graph does not contain any self-loop and there is at most one edge and at least one path between every two vertices. Furthermore, the network also meets the condition there are at most two non-intersect paths, which share no common edges, between every two vertices.

Wayne knows the bandwidth of each edge in that network but it is not enough for him. He needs plenty of statistic data to display, for example, he wants to know what the maximum data rate between every two vertices is. For the sake of clarity, vertices in that are numbered from 1 to n and the maximum bits each edge could transmit per second will be given. Your task is assisting him to calculate the value of the following formula:

∑1≤s< t≤n(s⊕t⊕flow(s,t)),

where ⊕ means the bitwise exclusive-OR operator and flow(s,t) means the maximum bits that could be transmitted per second between vertex s and vertex t.

Input
The first line contains one integer T, indicating the number of test cases.
The following lines describe all the test cases. For each test case:
The first line contains two integers n and m.
Each of the following m lines contains three integers u,v and w, indicating a bidirectional edge between vertex u and vertex v that can transmit at most w bits per second in each direction.
1≤T≤100, 1≤n≤105, n−1≤m≤32(n−1), 1≤u,v≤n, u≠v, 0≤w<109.
It is guaranteed that the sum of n in all test cases does not exceed 106 and the size of the standard input file does not exceed 26 MiB.

Output
For each test case, print the answer in one line.

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
题意:给出一个任意两点之间不重复路径不超过的图,求sum(s^t^flow(s,t));
做法:有一个结论,就是对于这样的图,那么一条边最多只会出现在一个环里面,那么只需要把环里面的最短边去掉,然后把环里剩余的边都加上这个边的权值,那么不会影响任意两点的最大流,对所有的环都这样操作,那么现在剩下的这个树上,任意两个节点的最大流,就是两点间边上最小的权值,那么把边的权值按照从大到小的顺序插入到图中,维护并查集,每次合并两个集合,nlogn复杂度。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
vector<pair<int,int> > G[N];
int num[N][32];
int pre[N];
int cnt[N];
int Find(int x){return x==pre[x]?x:pre[x]= Find(pre[x]);}
struct edge{
    int u,v,w;
    bool operator<(const edge& p)const{
        return w > p.w;
    }
};
vector<edge> vp;
int f[N],lf[N];
bool vis[N];
int tme[N];
int tot = 0;
void dfs(int x){
    //cout << x << endl;
    tme[x] = ++tot;
    vis[x] = true;
    for(int i = 0;i < G[x].size();i ++){

        int v = G[x][i].first;
        if(v == f[x]||vis[v] && tme[v] > tme[x]) continue;
        if(vis[v]){
            //cout << x << ' '<< v << endl;
            int mn = G[x][i].second;
            int tmp = x;
            while(tmp != v){
                mn = min(mn,lf[tmp]);
                tmp = f[tmp];
            }

            bool sg = true;
            tmp = x;
            if(G[x][i].second == mn){
                sg = false;
            }
            else{
                vp.push_back({x,v,G[x][i].second+mn});
            }
            while(tmp != v){
                if(sg&&lf[tmp] == mn){
                    sg = false;
                    lf[tmp] = -1;
                }
                else{
                    vp.push_back({tmp,f[tmp],lf[tmp]+mn});
                    lf[tmp] = -1;
                }
                tmp = f[tmp];
            }
        }
        else{
            f[v] = x;
            lf[v] = G[x][i].second;
            dfs(v);
        }
    }
}
int main(){
    int T;
    cin >>T;
    while(T--){
        tot = 0;
        int n,m;
        scanf("%d %d",&n,&m);
        for(int i = 1;i <= n;i ++) G[i].clear();
        for(int i = 1;i <= m;i ++){
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            G[u].push_back({v,w});
            G[v].push_back({u,w});
        }
        vp.clear();
        memset(vis,false,sizeof(vis));
        memset(lf,-1,sizeof(lf));

        dfs(1);
        for(int i = 1;i <= n;i ++){
            if(lf[i] != -1){
                vp.push_back({i,f[i],lf[i]});
            }
        }
        sort(vp.begin(),vp.end());
        for(int i = 1;i <= n;i ++) pre[i] = i,cnt[i] = 1;
        for(int i = 1;i <= n;i ++){
            for(int j= 0;j < 31;j ++){
                num[i][j] = (i>>j)&1;
            }
        }
        unsigned long long ans = 0;
        for(int i = 0;i < vp.size();i ++){
            edge e = vp[i];
            int w= e.w;
            int fa = Find(e.u),fb = Find(e.v);
            for(int i = 0;i < 31;i ++){
                unsigned long long t = (w>>i)&1;
                ans += ((t^1^1)<<i)*num[fa][i]*num[fb][i];
                ans += ((t^1^0)<<i)*num[fa][i]*(cnt[fb]-num[fb][i]);
                ans += ((t^0^1)<<i)*(cnt[fa]-num[fa][i])*num[fb][i];
                ans += ((t^0^0)<<i)*(cnt[fa]-num[fa][i])*(cnt[fb]-num[fb][i]);
                num[fa][i] += num[fb][i];
            }
            cnt[fa] += cnt[fb];
            pre[fb] = fa;
        }
        printf("%llu\n",ans);
    }



    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值