题意:给一张n个点m条边的连通图,每条边(ai,bi)有一个权值wi和费用ci,
表示这条边每降低1的权值需要ci的花费。现在一共有S费用可以用来降低某些边的权值
(可以降到负数),求图中的一棵权值和最小的生成树并输出方案
显然是找到一条边然后将这条边减到最小
先跑一边最小生成树,找到树上最小的一点,然后在枚举其他的边,
加上这条边会产生一个环,所以需要删除这个环上面权值最大的边
这个通过类似于LCA倍增的手法做到,
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <iostream> 8 #include <map> 9 #include <stack> 10 #include <string> 11 #include <vector> 12 #define pi acos(-1.0) 13 #define eps 1e-6 14 #define fi first 15 #define se second 16 #define rtl rt<<1 17 #define rtr rt<<1|1 18 #define bug printf("****** ") 19 #define mem(a,b) memset(a,b,sizeof(a)) 20 #define name2str(x) #x 21 #define fuck(x) cout<<#x" = "<<x<<endl 22 #define f(a) a*a 23 #define sf(n) scanf("%d", &n) 24 #define sff(a,b) scanf("%d %d", &a, &b) 25 #define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c) 26 #define sffff(a,b,c,d) scanf("%d %d %d %d", &a, &b, &c, &d) 27 #define pf printf 28 #define FRE(i,a,b) for(i = a; i <= b; i++) 29 #define FREE(i,a,b) for(i = a; i >= b; i--) 30 #define FRL(i,a,b) for(i = a; i < b; i++)+ 31 #define FRLL(i,a,b) for(i = a; i > b; i--) 32 #define FIN freopen("data.txt","r",stdin) 33 #define gcd(a,b) __gcd(a,b) 34 #define lowbit(x) x&-x 35 using namespace std; 36 typedef long long LL; 37 typedef unsigned long long ULL; 38 const int mod = 1e9 + 7; 39 const int maxn = 2e5 + 10; 40 const int INF = 0x3f3f3f3f; 41 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL; 42 int n, m, c[maxn], w[maxn], fa[maxn], vis[maxn]; 43 int dep[maxn], p[maxn][21], maxx[maxn][21]; 44 struct Edge { 45 int u, v, w, id; 46 } edge[maxn]; 47 int cmp ( Edge a, Edge b ) { 48 return a.w < b.w; 49 } 50 struct xxx { 51 int v, id; 52 xxx ( int v, int id ) : v ( v ), id ( id ) {} 53 }; 54 vector<xxx>mp[maxn]; 55 int Find ( int x ) { 56 return fa[x] == x ? x : fa[x] = Find ( fa[x] ); 57 } 58 void dfs ( int u, int f, int id ) { 59 dep[u] = dep[f] + 1, p[u][0] = f, maxx[u][0] = id; 60 for ( int i = 1 ; i <= 20 ; i++ ) { 61 if ( dep[u] - ( 1 << i ) <= 0 ) break; 62 int v = p[u][i - 1]; 63 p[u][i] = p[v][i - 1]; 64 if ( w[maxx[u][i - 1]] < w[maxx[v][i - 1]] ) maxx[u][i] = maxx[v][i - 1]; 65 else maxx[u][i] = maxx[u][i - 1]; 66 } 67 for ( int i = 0 ; i < mp[u].size() ; i++ ) { 68 int v = mp[u][i].v, id = mp[u][i].id; 69 if ( v != f ) dfs ( v, u, id ); 70 } 71 } 72 int get_max ( int x, int y ) { 73 if ( dep[x] < dep[y] ) swap ( x, y ); 74 int temp = 0, ans = 0; 75 for ( int i = 20 ; i >= 0 ; i-- ) { 76 if ( dep[x] - ( 1 << i ) >= dep[y] ) { 77 if ( w[maxx[x][i]] > temp ) ans = maxx[x][i], temp = w[ans]; 78 x = p[x][i]; 79 } 80 } 81 if ( x == y ) return ans; 82 for ( int i = 20 ; i >= 0 ; i-- ) { 83 if ( dep[x] - ( 1 << i ) > 0 && p[x][i] != p[y][i] ) { 84 if ( w[maxx[x][i]] > temp ) ans = maxx[x][i], temp = w[ans]; 85 if ( w[maxx[y][i]] > temp ) ans = maxx[y][i], temp = w[ans]; 86 x = p[x][i], y = p[y][i]; 87 if ( x == y ) break; 88 } 89 } 90 if ( w[maxx[x][0]] > temp ) ans = maxx[x][0], temp = w[ans]; 91 if ( w[maxx[y][0]] > temp ) ans = maxx[y][0], temp = w[ans]; 92 return ans; 93 } 94 int main() { 95 sff ( n, m ); 96 for ( int i = 1 ; i <= m ; i++ ) sf ( w[i] ); 97 for ( int i = 1 ; i <= m ; i++ ) sf ( c[i] ); 98 for ( int i = 1 ; i <= m ; i++ ) { 99 sff ( edge[i].u, edge[i].v ); 100 edge[i].w = w[i], edge[i].id = i; 101 } 102 sort ( edge + 1, edge + 1 + m, cmp ); 103 LL sum = 0, s, minn = INF, idx = 0, k = 0; 104 scanf ( "%lld", &s ); 105 for ( int i = 1 ; i <= n ; i++ ) fa[i] = i; 106 for ( int i = 1 ; i <= m ; i++ ) { 107 int nx = Find ( edge[i].v ), ny = Find ( edge[i].u ); 108 if ( nx == ny ) continue; 109 fa[nx] = ny; 110 sum += edge[i].w; 111 vis[edge[i].id] = 1, k++; 112 if ( c[edge[i].id] < minn ) idx = edge[i].id, minn = c[edge[i].id]; 113 mp[edge[i].u].push_back ( xxx ( edge[i].v, edge[i].id ) ); 114 mp[edge[i].v].push_back ( xxx ( edge[i].u, edge[i].id ) ); 115 if ( k == n - 1 ) break; 116 } 117 LL ans = sum - s / minn; 118 dep[0] = 0; 119 dfs ( 1, 0, 0 ); 120 int del = 0; 121 for ( int i = 1 ; i <= m ; i++ ) { 122 if ( vis[edge[i].id] ) continue; 123 int cnt = get_max ( edge[i].u, edge[i].v ); 124 if ( cnt == 0 ) continue; 125 LL temp = sum - w[cnt] + w[edge[i].id] - s / c[edge[i].id]; 126 if ( temp < ans ) ans = temp, idx = edge[i].id, del = cnt; 127 } 128 if ( del ) vis[del] = 0, vis[idx] = 1; 129 printf ( "%lld ", ans ); 130 w[idx] -= s / c[idx]; 131 for ( int i = 1 ; i <= m ; i++ ) if ( vis[i] ) printf ( "%d %d ", i, w[i] ); 132 return 0; 133 }