【题目链接】
【算法】
先求出图的最小生成树
枚举不在最小生成树上的边,若加入这条边,则形成了一个环,如果在环上且在最小生成树上的权值最大的边等于
这条边的权值,那么,显然最小生成树不唯一
树上倍增可以解决这个问题
【代码】
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
#include <stack>
#include <limits.h>
using namespace std;
#define MAXN 110
#define MAXM 1000010
#define MAXLOG 20
struct Edge
{
int x,y;
long long w;
} edge[MAXM];
int T,n,m,i;
long long val;
vector< pair<int,long long> > e[MAXN];
bool on_mst[MAXM];
int fa[MAXN],anc[MAXN][MAXLOG],dep[MAXN];
long long mx[MAXN][MAXLOG];
bool not_unique;
inline bool cmp(Edge a,Edge b) { return a.w < b.w; }
inline int get_root(int x)
{
if (fa[x] == x) return x;
return fa[x] = get_root(fa[x]);
}
inline void kruskal()
{
int i,x,y,sx,sy;
long long w;
for (i = 1; i <= n; i++) fa[i] = i;
for (i = 1; i <= m; i++) on_mst[i] = false;
sort(edge+1,edge+m+1,cmp);
for (i = 1; i <= m; i++)
{
x = edge[i].x;
y = edge[i].y;
w = edge[i].w;
sx = get_root(x);
sy = get_root(y);
if (sx != sy)
{
on_mst[i] = true;
val += w;
fa[sx] = sy;
e[x].push_back(make_pair(y,w));
e[y].push_back(make_pair(x,w));
}
}
}
inline void build(int u)
{
int i,v;
for (i = 1; i < MAXLOG; i++)
{
anc[u][i] = anc[anc[u][i-1]][i-1];
mx[u][i] = max(mx[u][i-1],mx[anc[u][i-1]][i-1]);
}
for (i = 0; i < e[u].size(); i++)
{
v = e[u][i].first;
if (anc[u][0] != v)
{
dep[v] = dep[u] + 1;
anc[v][0] = u;
mx[v][0] = e[u][i].second;
build(v);
}
}
}
inline long long get(int x,int y)
{
int i,t;
long long ans = 0;
if (dep[x] > dep[y]) swap(x,y);
t = dep[y] - dep[x];
for (i = 0; i < MAXLOG; i++)
{
if (t & (1 << i))
{
ans = max(ans,mx[y][i]);
y = anc[y][i];
}
}
if (x == y) return ans;
for (i = MAXLOG - 1; i >= 0; i--)
{
if (anc[x][i] != anc[y][i])
{
ans = max(ans,max(mx[x][i],mx[y][i]));
x = anc[x][i];
y = anc[y][i];
}
}
return max(ans,max(mx[x][0],mx[y][0]));
}
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
val = 0;
not_unique = false;
for (i = 1; i <= n; i++)
{
dep[i] = 0;
e[i].clear();
memset(anc[i],0,sizeof(anc[i]));
memset(mx[i],0,sizeof(mx[i]));
}
for (i = 1; i <= m; i++) scanf("%d%d%lld",&edge[i].x,&edge[i].y,&edge[i].w);
kruskal();
build(1);
for (i = 1; i <= m; i++)
{
if (!on_mst[i])
not_unique |= (get(edge[i].x,edge[i].y) == edge[i].w);
}
if (not_unique) printf("Not Unique!\n");
else printf("%lld\n",val);
}
return 0;
}