codeforces733E LCA在线

来源:互联网 发布:树莓派安装rpm软件 编辑:程序博客网 时间:2024/06/10 20:24

题目链接如下:http://codeforces.com/problemset/problem/733/F

算法思路

这道题让我又加深了一下对于倍增二分求LCA的原理.
很显然,要让每两个城市之间两两可达,需要构造一棵最小生成树。但是我们在这里可以使用一定的钱减少一些边的dissatisfation,而且这个值可以为负值,很显然我们要选择的就是成本最小的那一条边.这样的话,我们先使用最小生成树算法构造出最小生成树,然后对于每条边,加入最小生成树之后会构成环,所以对于每个环,我们要计算出这个环上权值最大的边。
这里使用的就是倍增,二分的方法,dp[i][j]表示的是第i个结点以上2j层的祖先,那么对于两个不同深度的点,先将它们提升到同一个高度,然后在二分最长的边,具体的做法如下:

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<utility>#include<vector>using namespace std;#define MAXN 200005#define LL long long#define INF 0x3f3f3f3f3f3f3f3fstruct Edge{    int u,v;    int index;    LL c,w;}EdgeTable[MAXN];int n,m;LL k,tot;vector<pair<int,int> >grid[MAXN];int fa[MAXN];int height[MAXN],psb[MAXN][22];LL dsb[MAXN][22];bool comp(Edge a,Edge b){    return a.w<b.w;}int find_dad(int cur){    if(fa[cur]==cur)return cur;    else return fa[cur]=find_dad(fa[cur]);}void Kruskal(){    int i;    int num=0;    sort(EdgeTable+1,EdgeTable+1+m,comp);    tot=0;    for(i=1;i<=n;i++)        fa[i] = i;    for(i=1;i<=m;i++){        int u = EdgeTable[i].u;        int v = EdgeTable[i].v;        int fau = find_dad(u);        int fav = find_dad(v);        if(fau == fav)continue;        else{            tot += EdgeTable[i].w;            fa[fau] = fav;            grid[u].push_back(make_pair(v,i));            grid[v].push_back(make_pair(u,i));            num++;            if(num==n-1)break;        }    }    return;}void Dfs(int cur,int fa){    int i,j,k;    for(i=0;i<grid[cur].size();i++){        j = grid[cur][i].first;        k = grid[cur][i].second;        if(j!=fa){            height[j] = height[cur]+1;            psb[j][0] = cur;            dsb[j][0] = EdgeTable[k].w;            Dfs(j,cur);        }    }    return;}LL query(int a,int b){    int i=0;    LL ans = 0;    if(height[a]>height[b])return query(b,a);    for(i=19;i>=0;i--){        if(height[b]-(1<<i)>=height[a]){            ans = max(ans,dsb[b][i]);            b = psb[b][i];        }    }    if(a==b)return ans;    for(i=19;i>=0;i--){        if(psb[a][i]!=psb[b][i]){            ans = max(dsb[a][i],ans);            ans = max(dsb[b][i],ans);            a = psb[a][i];            b = psb[b][i];        }    }    return max(ans,max(dsb[a][0],dsb[b][0]));}void Solve(){    memset(psb,-1,sizeof(psb));    Kruskal();    height[1]=1;    Dfs(1,-1);    int i,j;    LL ans = INF;    int select = 1;    for(i=1;i<20;i++){        for(j=1;j<=n;j++){            if(psb[j][i-1]>=0){                psb[j][i] = psb[psb[j][i-1]][i-1];                dsb[j][i] = max(dsb[j][i-1],dsb[psb[j][i-1]][i-1]);            }        }    }    for(i=1;i<=m;i++){        //cout << ans << endl;        LL tmp = tot - query(EdgeTable[i].u,EdgeTable[i].v) - k/EdgeTable[i].c + EdgeTable[i].w;        if(tmp<ans){            ans = tmp;            select = i;        }    }    printf("%lld\n",ans);    for(i=1;i<=n;i++)        fa[i]=i;    fa[EdgeTable[select].u] = EdgeTable[select].v;    printf("%d %lld\n",EdgeTable[select].index,EdgeTable[select].w-k/EdgeTable[select].c);    int num=1;    for(i=1;i<=m;i++){        int u = EdgeTable[i].u;        int v = EdgeTable[i].v;        int fau = find_dad(u);        int fav = find_dad(v);        if(fau == fav)continue;        else{            printf("%d %lld\n",EdgeTable[i].index,EdgeTable[i].w);            fa[fau] = fav;            num++;            if(num==n-1)break;        }    }    return;}int main(){    //freopen("input","r",stdin);    int i;    scanf("%d%d",&n,&m);    for(i=1;i<=m;i++){        scanf("%lld",&EdgeTable[i].w);        EdgeTable[i].index=i;    }    for(i=1;i<=m;i++)        scanf("%lld",&EdgeTable[i].c);    for(i=1;i<=m;i++)        scanf("%d%d",&EdgeTable[i].u,&EdgeTable[i].v);    scanf("%lld",&k);    Solve();    return 0;}
0 0
原创粉丝点击