【NOIP模拟】roads(最短路径转最小生成树)

题目背景

SOURCE:NOIP2016-RZZ-1

题目描述

有 N 个城市,这些城市通过 M 条无向边互相连通,每条边有一个权值 Ci ,表示这条边的长度为 2^(Ci) ,没有两条边的长度是相同的。

设 d(i,j)为城市 i 到城市 j 的最短路长度,求:

    

答案以二进制输出。

输入格式

第一行,两个正整数 N ,M 。
接下来 M 行,每行三个正整数 Ai,Bi,Ci ,表示城市 Ai,Bi 间有一条权值为 Ci 的无向边。

输出格式

输出一个二进制数,表示所有无序点对间的最短路长度之和(即问题描述中的式子)。

样例数据 1

输入

5 6 
1 3 5 
4 5 0 
2 1 3 
3 2 1 
4 3 4 
4 2 2

输出

1000100

备注

【样例解释】

【数据规模与约定】

对于 30% 的数据,N,M≤50。
对于 60% 的数据,N,M≤100。
对于 80% 的数据,N≤2000;M≤10000。
对于 100% 的数据,1≤N≤105;1≤M≤2×105;1≤Ai,Bi≤N,Ai≠Bi,0≤Ci<M。

【题目分析】

题意很简单。通过分析可以发现求得的所有最短路径都在图的最小生成树上。

最小生成树上的每一条边被走的次数为该边两端的子树大小之积$(t)$,又因为边权为二进制数$2^c$,

给出$c$,那么我们就可以在答案数组里的第$c$位加上$t$,答案数组表示的时答案的二进制。

最后将答案数组写一遍高精度二进制进位即可。

【CODE】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;

const int N = 1e5 + 5, M = 2e5 + 5;
int n, m;
int ecnt;
struct node{
    int len, st, ed;
    friend bool operator < (const node &a, const node &b){
        return a.len < b.len;
    }
}edge[M];
int adj[N], go[M << 1], len[M << 1], nxt[M << 1];
int sze[N];
long long ans[M * 2 + 30];
int fa[N];

inline int getF(int x){
    return x == fa[x] ? x : (fa[x] = getF(fa[x]));
}

inline void Merge(int u, int v){
    int fu = getF(u), fv = getF(v);
    if(fu != fv) fa[fu] = fv;
}

inline void addEdge(int u, int v, int l){
    ecnt++;
    edge[ecnt].len = l;
    edge[ecnt].st = u, edge[ecnt].ed = v;
}

inline void addEdge2(int u, int v, int l){
    nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v, len[ecnt] = l;
    nxt[++ecnt] = adj[v], adj[v] = ecnt, go[ecnt] = u, len[ecnt] = l;
}

inline void dfs(int u, int f){
    sze[u] = 1;
    int v;
    for(int e = adj[u]; e; e = nxt[e]){
        if((v = go[e]) == f) continue;
        dfs(v, u);
        sze[u] += sze[v];
    }
}

inline void dfs2(int u, int f){
    int v;
    for(int e = adj[u]; e; e = nxt[e]){
        if((v = go[e]) == f) continue;
        ans[len[e]] += (long long)sze[v] * (n - sze[v]);
        dfs2(v, u);
    }
}

inline void printAns(){
    int i, x;
    for(i = 0; i <= m + 1000; i++){
        ans[i + 1] += ans[i] / 2;
        ans[i] %= 2;
    }
    for(; i >= 1; i--) if(ans[i]) break;
    for(; i >= 0; i--)
        cout<<ans[i];
}

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i++){
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        addEdge(a, b, c);
    }
    sort(edge + 1, edge + m + 1);
    ecnt = 0;
    for(int i = 1; i <= n; i++) fa[i] = i;
    for(int i = 1; i <= m; i++){
        if(getF(edge[i].st) != getF(edge[i].ed)){
            addEdge2(edge[i].st, edge[i].ed, edge[i].len);
            Merge(edge[i].st, edge[i].ed);<<edge[i].ed<<endl;
        }
    }
    dfs(1, 0);
    dfs2(1, 0);
    printAns();
    return 0;
}
View Code

 

posted @ 2017-07-22 20:41  CzYoL  阅读(175)  评论(0编辑  收藏  举报