题意:
给出一张无向图,每条边有权值,现在可以减小某些边的权值,目的是让这张图的最小生成树权值尽可能小,而将第i条边的权值-1需要花费costi的代价,最多只能花费s的代价,请找出一种方案,使得在这个s的代价内让最小生成树的权值尽可能小,并打印出你选择的边和他们的最终权值,如果有多解,任意输出一种即可
solution:
其实还是可做的。。
先对原图求一个最小生成树,把选择的边拿出来,做成一棵树
题目允许我们修改某些边的权值,那么假设我们拿到了一个最优方案,完全可以让所有修改都发生在其中那条最便宜的边上,,这样总能使得答案至少不会变差
假设我们让所有操作都发生在第i条边上,而我们已经做成了一棵原图最小生成树
把这条新边加入这棵树,得到一个环,环上一定有一条边权值最大,那就不要它,用这条新边,看看答案是否能够更优就好了
啊。。这样做正确性显然。。。。。。。反正是对的,嗯。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 2E5 + 20;
typedef long long LL;
struct E{
int to,w,Num; E(){}
E(int to,int w,int Num): to(to),w(w),Num(Num){}
};
struct E2{
int x,y,w,Num; E2(){}
E2(int x,int y,int w,int Num): x(x),y(y),w(w),Num(Num){}
bool operator < (const E2 &b) const {return w < b.w;}
}edgs[maxn];
int n,m,s,w[maxn],f[maxn],F[maxn],p1,p2,g,Max,pos,
L[maxn],fa[maxn][20],c[maxn][20],num[maxn][20];
bool bo[maxn];
LL ans,Ans;
vector <E> v[maxn];
void Dfs(int x,int from)
{
for (int i = 1; i < 20; i++) {
fa[x][i] = fa[fa[x][i-1]][i-1];
if (c[x][i-1] < c[fa[x][i-1]][i-1])
c[x][i] = c[fa[x][i-1]][i-1],num[x][i] = num[fa[x][i-1]][i-1];
else c[x][i] = c[x][i-1],num[x][i] = num[x][i-1];
}
for (int i = 0; i < v[x].size(); i++) {
E e = v[x][i];
if (e.to == from) continue;
L[e.to] = L[x] + 1;
fa[e.to][0] = x;
c[e.to][0] = e.w;
num[e.to][0] = e.Num;
Dfs(e.to,x);
}
}
void LCA(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
int Log; for (Log = 0; L[p] - (1<<Log) > 0; Log++); --Log;
for (int j = Log; j >= 0; j--)
if (L[p] - (1<<j) >= L[q]) {
if (c[p][j] > Max)
Max = c[p][j],pos = num[p][j];
p = fa[p][j];
}
if (p == q) return;
for (int j = Log; j >= 0; j--)
if (fa[p][j] != fa[q][j]) {
if (c[p][j] > Max)
Max = c[p][j],pos = num[p][j];
if (c[q][j] > Max)
Max = c[q][j],pos = num[q][j];
p = fa[p][j]; q = fa[q][j];
}
if (c[p][0] > Max)
Max = c[p][0],pos = num[p][0];
if (c[q][0] > Max)
Max = c[q][0],pos = num[q][0];
}
int getfa(int k) {return k == F[k]?k:F[k] = getfa(F[k]);}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n >> m;
for (int i = 1; i <= n; i++) F[i] = i;
for (int i = 1; i <= m; i++) scanf("%d",&w[i]);
for (int i = 1; i <= m; i++) scanf("%d",&f[i]);
for (int i = 1; i <= m; i++) {
int x,y; scanf("%d%d",&x,&y);
edgs[i] = E2(x,y,w[i],i);
}
sort(edgs + 1,edgs + m + 1);
for (int i = 1; i <= m; i++) {
int fx = getfa(edgs[i].x);
int fy = getfa(edgs[i].y);
if (fx == fy) continue;
F[fx] = fy; bo[i] = 1;
ans += 1LL*edgs[i].w;
v[edgs[i].x].push_back(E(edgs[i].y,edgs[i].w,edgs[i].Num));
v[edgs[i].y].push_back(E(edgs[i].x,edgs[i].w,edgs[i].Num));
}
L[1] = 0; Dfs(1,0); Ans = ans; cin >> s;
for (int i = 1; i <= m; i++) {
int G = edgs[i].w - s/f[edgs[i].Num];
Max = 0; LCA(edgs[i].x,edgs[i].y);
if (ans > Ans + 1LL*(G - Max)) {
ans = Ans + 1LL*(G - Max);
g = G; p1 = pos; p2 = edgs[i].Num;
}
}
cout << ans << endl;
if (p2) cout << p2 << ' ' << g << endl;
for (int i = 1; i <= m; i++)
if (bo[i] && edgs[i].Num != p1)
printf("%d %d\n",edgs[i].Num,edgs[i].w);
return 0;
}