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;
}

猜你喜欢

转载自blog.csdn.net/zstu_zy/article/details/81480464
今日推荐