Loading

CF733F

Description

给出一张 \(n\) 个点 \(m\) 条边的无向图,每条边 \((a_i,b_i)\) 有一个权值 \(w_i\) 和费用 \(c_i\),表示这条边 每降低 \(1\) 的权值需要 \(c_i\) 的花费。现在一共有 \(S\) 费用可以用来降低某些边的权值(可以降到负数),求图中的一棵权值和最小的生成树并输出方案

Solution

本题就是一个求最小生成树加不定边的题目,而且输出多了个方案

题目中信息很多,在这里先总结一下:

  1. 最多降低权值为 \(\large\frac{S}{c_i}\)
  2. 既然可以用 \(S\) 费用来降低 \(\large\frac{S}{c_i}\) 的权值,而且可以降到负数,本题又是求最小生成树,那就一直降一条边就好了(保证降完后本条边是在生成树里的)
  3. 要求输出方案,就需要存储树上的是第几条边以及他的权值

好像就这么点信息也不是很多

那么我们想想该怎么做

我们知道,本题肯定是先求最小生成树,然后再枚举边看是否替换并比较最优方案

枚举边有两种情况,一种是树边,另一种是非树边

对于树边,既然已经在树上,答案就可以直接把最小生成树权值和减去降低的权值拿来比较

另一方面,最多减低 \(\large\frac{S}{c_i}\) 的权值,那 \(c_i\) 肯定越小越好,所以在树内的边我们就降低 \(c\) 最小的那一条

对于非树边时,把这条边与环上最大的树边比较,如果树边更大就减去这条树边

当不用换边时,直接输出原树的信息

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<algorithm>
#define maxn 200005
#define INF 1000000000000000000

using namespace std;

int n,m;
bool vis[maxn*2],v[maxn*2];
long long f[maxn][26],depth[maxn];
long long tot,head[maxn*4],fa[maxn],S,ans,num,cnt,sum,flag,lkp,fjh;
struct ma{long long dis,bh;}maxi[maxn][26];
struct node{long long dis,c,fr,to,bh,nxt;}a[maxn*4],e[maxn*4];
inline long long cmp(node a,node b){return a.dis<b.dis;}

inline void add(long long fr,long long to,long long dis,long long c,long long bh){
    e[++tot].to=to;e[tot].fr=fr;e[tot].dis=dis;
    e[tot].bh=bh;e[tot].c=c;e[tot].nxt=head[fr];
    head[fr]=tot;
}

inline long long Getf(long long x){
    if(fa[x]==x) return x;
    return fa[x]=Getf(fa[x]);
}

inline void hb(long long x,long long y){
    x=Getf(x);y=Getf(y);
    if(x!=y) fa[y]=x;
}

inline bool pd(long long x,long long y){
    x=Getf(x);y=Getf(y);
    return x==y; 
}

inline void dfs(long long now,long long p){ 
    f[now][0]=p;
    for(long long i=head[now];i;i=e[i].nxt){
        long long to=e[i].to;
        if(to==f[now][0]) continue;
        depth[to]=depth[now]+1ll;
            maxi[to][0].dis=e[i].dis;
            maxi[to][0].bh=e[i].bh;
            dfs(to,now);
    }
}

inline void caq(){
    for(int i=1;i<=25;++i)
        for(int j=1;j<=n;++j){
            f[j][i]=f[f[j][i-1]][i-1];
            if(maxi[j][i-1].dis>maxi[f[j][i-1]][i-1].dis){
                maxi[j][i].dis=maxi[j][i-1].dis;
                maxi[j][i].bh=maxi[j][i-1].bh;
            }
            else{
                maxi[j][i].dis=maxi[f[j][i-1]][i-1].dis;
                maxi[j][i].bh=maxi[f[j][i-1]][i-1].bh;
            }
        }
}

inline long long lca(long long x,long long y){
    if(depth[x]<depth[y]) swap(x,y);
    for(int i=25;i>=0;--i)
        if(depth[f[x][i]]>=depth[y]) 
            x=f[x][i];
    if(x==y) return x;
    for(int i=25;i>=0;--i)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}

inline ma get_max(long long u,long long v){
    ma Ans;
    Ans.bh=-1;Ans.dis=-INF;
    for(int i=25;i>=0;--i){
        if(depth[f[u][i]]>=depth[v]){
            if(Ans.dis<maxi[u][i].dis){
                Ans.dis=maxi[u][i].dis;
                Ans.bh=maxi[u][i].bh;
            }
            u=f[u][i];
	}
    }
    return Ans;
}

int main(){
    cin>>n;cin>>m;
    for(int i=1;i<=m;i++) cin>>a[i].dis;
    for(int i=1;i<=m;i++) cin>>a[i].c;
    for(int i=1;i<=m;i++){cin>>a[i].fr>>a[i].to;a[i].bh=i;}
    cin>>S;for(int i=1;i<=n;i++) fa[i]=i;sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;i++){
        if(!pd(a[i].fr,a[i].to)) continue;
        hb(a[i].fr,a[i].to);
	add(a[i].fr,a[i].to,a[i].dis,a[i].c,i);
        add(a[i].to,a[i].fr,a[i].dis,a[i].c,i);
        sum+=a[i].dis;vis[i]=1;v[i]=1;
    }
    depth[1]=1;
    maxi[1][0].dis=-INF;
    maxi[1][0].bh=e[1].bh;
    dfs(1,1);caq();cnt=INF;
    for(long long i=1;i<=m;i++){
        long long ww=S/a[i].c;
        if(vis[i]){
            if(cnt>sum-ww)flag=i;
            cnt=min(sum-ww,cnt);
        }
        else{
            long long fr=a[i].fr,to=a[i].to,lcaa=lca(fr,to);
            ma maxu=get_max(fr,lcaa),maxv=get_max(to,lcaa);
            if(maxu.dis>maxv.dis){
                if(cnt>sum-maxu.dis+a[i].dis-ww){
                    cnt=sum-maxu.dis+a[i].dis-ww;
                    v[lkp]=v[maxu.bh]=0;v[fjh]=v[i]=1;
                    lkp=i;fjh=maxu.bh;flag=i;
                }
            }
            else{
                if(cnt>sum-maxv.dis+a[i].dis-ww){
                    cnt=sum-maxv.dis+a[i].dis-ww;
                    v[lkp]=v[maxv.bh]=0;v[fjh]=v[i]=1;
                    lkp=i;fjh=maxv.bh;flag=i;
                }
            }
        }
    }
    if(flag) a[flag].dis=a[flag].dis-(S/a[flag].c);
    printf("%lld\n",cnt);for(int i=1;i<=m;i++)
    if(v[i]) printf("%lld %lld\n",a[i].bh,a[i].dis);
    return 0;
}
posted @ 2020-11-06 09:55  KnightL  阅读(91)  评论(0编辑  收藏  举报