题意:在10000个点的一个无向图中,定义P = 删除某条边之后有多少点对因此不连通,那么给每一条边定义一个val值,val = P*len,len 就是本身这条边自己的长度,每一条边的val就是维护费用要求连接这条边的两个点中的一个点来承担,现在每个城市最初有一个 初始的维护费用,问 怎么样的一个分配方案能取到 每个城市的维护费用最大值最小。
解法:
很明显桥边具有val值,其他边是没有的,直接先进行一次双联通,形成一棵树,进行一次树形dp,统计子树的节点个数,这样就能统计出每一条桥边的val值,之后就是要统计最大的最小值是多少, 用二分来解,可以想到因为都是桥边构成的,所以必定没有换,那么就先对度为1 的边进行处理,如果能放到边上,就优先放在边上,这样类似一个拓扑序,一遍处理完所有的边,这样就可以判断出这个值是不是合法的。
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <memory.h>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
#define maxn 10010
typedef pair<int,int> PII;
typedef long long LL;
vector<PII> G[maxn] ,suo[maxn];
int n ,m;
LL cost[maxn];
void read() {
for(int i = 1;i <= n;i++)
scanf("%lld",cost + i);
int u ,v, w;
for(int i = 0 ;i < m; i++) {
scanf("%d%d%d", &u, &v, &w);
G[u].push_back( make_pair(v ,w));
G[v].push_back( make_pair(u ,w));
}
}
int num[maxn], kuainum[maxn];
int belong[maxn];
int ji ;
PII road[2 * maxn];
LL edgecost[2 * maxn];
struct BCC{
int dfs_clock, bcc_cnt;
int dfn[maxn], low[maxn], bccno[maxn];
stack<int> S;
void init() {
dfs_clock = bcc_cnt = 0;
for(int i = 1;i <= n;i++)
G[i].clear();
memset( dfn, 0, sizeof(dfn));
while(! S.empty())
S.pop();
}
int kuai ;
void dfs(int u,int fa) {
int size = G[u].size() ,x,flag = 1;
S.push(u);
dfn[u] = low[u] = ++ dfs_clock;
for(int i = 0 ;i < size; i++) {
int v = G[u][i].first;
if(v == fa && 1 == flag) {
flag = 0;
continue;
}
if(0 == dfn[v]) {
dfs(v,u);
low[u] = min(low[u], low[v]);
}
else
low[u] = min(low[u] ,dfn[v]);
}
if(low[u] == dfn[u]) {
bcc_cnt ++;
num[bcc_cnt] = 0;
belong[bcc_cnt] = kuai;
do{
x = S.top();
S.pop();
bccno[x] = bcc_cnt;
num[bcc_cnt] ++;
kuainum[kuai] ++;
}while(x != u);
}
}
void find_bcc() {
kuai = 0;
for(int i = 1;i <= n;i++)
if(0 == dfn[i]) {
kuai ++;
kuainum[kuai] = 0;
dfs(i, -1);
}
}
void build() {
ji = 0;
for(int i = 1;i <= n;i++) {
int size = G[i].size();
for(int f = 0 ;f < size;f++) {
int x = i;
int y = G[i][f].first;
if(x > y)
continue;
int len = G[i][f].second;
int u = bccno[x];
int v = bccno[y];
if(u == v)
continue;
suo[u].push_back( make_pair(v,ji));
suo[v].push_back( make_pair(u,ji));
road[ji] = make_pair(x, y);
edgecost[ji] = len;
ji ++;
}
}
}
}townboy;
int sum ;
bool vis[maxn];
int dfs(int rt ) {
vis[rt] = true;
int size = suo[rt].size();
int ret = num[rt];
for(int i = 0 ;i < size;i ++) {
int v = suo[rt][i].first;
if(true == vis[v])
continue;
int id = suo[rt][i].second;
LL tmp = dfs(v);
edgecost[id] *= (LL) tmp * (kuainum[belong[v]] - tmp);
ret += tmp;
}
return ret;
}
void debug() {
for(int i = 0;i < ji; i++) {
cout << edgecost[i] << endl;
}
cout << "debug end " << endl;
}
#define INF 0x3f3f3f3f3f3f3f3fLL
vector<int> E[maxn];
LL now[maxn];
int du[maxn];
bool test(LL lim) {
queue<int> q;
for(int i = 0;i < ji;i++)
vis[i] = false;
for(int i = 1;i <= n;i++) {
now[i] = cost[i];
E[i].clear();
du[i] = 0;
}
for(int i = 0;i < ji;i++) {
int u = road[i].first ,v = road[i].second;
du[u] ++, du[v] ++;
E[u].push_back(i);
E[v].push_back(i);
}
for(int i = 1;i <= n;i++)
if(1 == du[i])
q.push(i);
while(!q.empty()) {
int u = q.front();
q.pop();
if(0 == du[u])
continue;
int size = E[u].size();
int fun;
for(int i = 0;i < size; i++) {
if(false == vis[E[u][i]]) {
fun = E[u][i];
break;
}
}
vis[fun] = true;
int v = (u ^ road[fun].first ^ road[fun].second);
du[u] --;
du[v] --;
if(now[u] + edgecost[fun] <= lim)
now[u] += edgecost[fun];
else if(now[v] + edgecost[fun] <= lim)
now[v] += edgecost[fun];
else
return false;
if(1 == du[v])
q.push(v);
}
return true;
}
LL solve() {
townboy.init();
read();
townboy.find_bcc();
sum = townboy.bcc_cnt;
for(int i = 1;i <= sum; i++)
suo[i].clear();
townboy.build();
memset(vis, false, sizeof(vis));
for(int i = 1;i <= sum; i++)
if(false == vis[i])
dfs(i);
LL l = -1 ,r = INF, mid;
for(int i = 1;i <= n;i++)
l = max(l, (LL)cost[i]);
l --;
while(l != r - 1) {
mid = (l + r ) / 2;
if(test(mid) == true)
r = mid;
else
l = mid;
}
return r;
}
int main() {
int cas;
freopen("D:\\in.txt","r",stdin);
freopen("D:\\a.txt","w",stdout);
cin >> cas;
for(int i = 0 ;i < cas; i++) {
cin >> n >> m;
printf("Case %d: ",i + 1);
cout << solve() << endl;
}
return 0;
}