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