题目大意:给你n个点,m条边,每个边都有一个权重w,每条边也有一个c表示,消耗c元可以把这条边的权重减1,求最多消耗s元的最小生成树。
思路:因为一条边的权重没有下限所以s元肯定是用在一条边上的。 那么我们先跑一个最小生成树,把这棵最小生成树建出来,然后我们枚举用了
s元之后的边,如果这条边不在树上那么加上这条边之后肯定形成了一个环,最优的方案肯定是删掉这个环中权值最大的边再次变成一棵树。
对于边(u,v)来说,如果把这条边加上,那么删掉的边肯定在,u到 lca(u,v) 和 v到 lca(u,v)中的权值最大的那条边。 可以用倍增快速找边,就能解决
这个问题啦。 码起来好麻烦啊,借鉴了某个学长的代码。。
1 #include<bits/stdc++.h> 2 #define fi first 3 #define se second 4 #define mk make_pair 5 #define ll long long 6 #define pll pair<ll,ll> 7 #define pil pair<int,ll> 8 #define pli pair<ll,int> 9 #define pii pair<int,int> 10 #define read(x) scanf("%d",&x) 11 #define sread(x) scanf("%s",x) 12 #define dread(x) scanf("%lf",&x) 13 #define lread(x) scanf("%lld",&x) 14 using namespace std; 15 16 const int N=2e5+7; 17 const int M=2e6+7; 18 const int inf=0x3f3f3f3f; 19 const ll INF=0x3f3f3f3f3f3f3f3f; 20 const int mod=1e9+7; 21 22 int n,m,tot,s,fa[N],depth[N],nx[N][20],mx[N][20]; 23 24 struct node 25 { 26 int u,v,w,c,id; 27 bool operator < (const node &rhs)const 28 { 29 return w<rhs.w; 30 } 31 }e[N<<1]; 32 33 bool cmp(node a,node b){ 34 return a.id<b.id; 35 } 36 vector<pii> edge[N]; 37 map<int,int> result; 38 39 int Find(int x) { 40 return x==fa[x]? x : fa[x]=Find(fa[x]); 41 } 42 43 ll kruscal() 44 { 45 ll ans=0; 46 for(int i=1;i<=n;i++) 47 fa[i]=i; 48 49 sort(e,e+m); 50 51 for(int i=0;i<m;i++) 52 { 53 int u=e[i].u,v=e[i].v,w=e[i].w; 54 int nx_u=Find(u); 55 int nx_v=Find(v); 56 if(nx_u!=nx_v) 57 { 58 edge[u].push_back(mk(v,e[i].id)); 59 edge[v].push_back(mk(u,e[i].id)); 60 61 fa[nx_u]=nx_v; 62 ans+=w; 63 result[e[i].id]=w; 64 } 65 } 66 67 sort(e,e+m,cmp); 68 69 return ans; 70 } 71 72 int getMxId(int a,int b) 73 { 74 if(a==-1) return b; 75 if(b==-1) return a; 76 return e[a].w>e[b].w? a : b; 77 } 78 void dfs(int u,int pre) 79 { 80 nx[u][0]=pre; 81 for(int i=1;i<20;i++) 82 { 83 if(nx[u][i-1]!=-1) 84 { 85 nx[u][i]=nx[nx[u][i-1]][i-1]; 86 mx[u][i]=getMxId(mx[u][i-1],mx[nx[u][i-1]][i-1]); 87 } 88 else 89 nx[u][i]=mx[u][i]=-1; 90 } 91 92 for(auto t : edge[u]) 93 { 94 int v=t.first; 95 if(v==pre) 96 continue; 97 depth[v]=depth[u]+1; 98 mx[v][0]=t.second; 99 100 dfs(v,u); 101 } 102 } 103 104 int getLca(int a,int b) 105 { 106 if(depth[a]<depth[b]) 107 swap(a,b); 108 for(int i=0;i<20;i++) 109 if(depth[a]-depth[b]>>i & 1) 110 a=nx[a][i]; 111 112 if(a==b) return a; 113 for(int i=19;i>=0;i--) 114 if(nx[a][i]!=nx[b][i]) 115 a=nx[a][i],b=nx[b][i]; 116 117 return nx[a][0]; 118 } 119 120 int getMxIdPath(int a,int b) 121 { 122 int lca=getLca(a,b); 123 int ret=-1; 124 for(int i=19;i>=0;i--) 125 { 126 if(nx[a][i]!=-1 && depth[nx[a][i]]>=depth[lca]) 127 { 128 ret=getMxId(ret,mx[a][i]); 129 a=nx[a][i]; 130 } 131 if(nx[b][i]!=-1 && depth[nx[b][i]]>=depth[lca]) 132 { 133 ret=getMxId(ret,mx[b][i]); 134 b=nx[b][i]; 135 } 136 } 137 return ret; 138 } 139 140 int main() 141 { 142 read(n); read(m); 143 144 for(int i=0;i<m;i++) 145 read(e[i].w); 146 147 for(int i=0;i<m;i++) 148 read(e[i].c); 149 150 for(int i=0;i<m;i++) 151 { 152 read(e[i].u); 153 read(e[i].v); 154 e[i].id=i; 155 } 156 157 read(s); 158 159 ll cost=kruscal(); 160 161 dfs(1,-1); 162 163 ll ans=cost, p=0; 164 165 for(int id=0;id<m;id++) 166 { 167 int big=getMxIdPath(e[id].u,e[id].v); 168 ll tmp=cost-e[big].w+e[id].w-s/e[id].c; 169 if(tmp<ans) 170 ans=tmp,p=id; 171 } 172 173 printf("%lld\n",ans); 174 result.erase(getMxIdPath(e[p].u,e[p].v)); 175 result[p]=e[p].w-s/e[p].c; 176 177 for(auto t: result) 178 printf("%d %d\n",t.first+1,t.second); 179 180 return 0; 181 } 182 /* 183 */