管理者(最小生成树+rmq)

题目大意:

       G同学是H市的管理者。H市有n个街区,m条双向道路,每条道路连接两个不同的街区,且没有两条道路连接两个一模一样的街区。保证任意两个街区能相互到达。
       由于H市交通拥堵问题日益严重,G同学必须选择其中若干条道路升级为高速公路。升级后必须保证如果只走高速公路,任意两个街区都能相互到达。当然,每条道路升级为高速公路有不同的费用。同时由于未来的城市发展需要,可能要求某一条道路必须升级。问假如第i条道路一定要升级(1≤i≤m),最小花费是多少。1≤n≤2*10^5,n-1≤m≤2*10^5,每一条边费用<=10^9。

输入样例:

5 7
1 2 3
1 3 1
1 4 5
2 3 2
2 5 3
3 4 2
4 5 4

输出样例:

9
8
11
8
8
8
9

题解:

       看到这道题,第一想法就是假如不强制某一条边一定要修建,那么就是一个简单的最小生成树问题。所以我们先建立一棵最小生成树,显然,假如一条边在这个最小生成树上,那么一定要修这条边的最小花费就是最小生成树的边权和。

       那么问题来了,如果一条边不在这个最小生成树上呢?因为一定要加这一条边,所以我们就把这条边加进去,于是会形成一个环,我们的任务就是把环上最长的边删掉。对于这样一个环,它有一个性质:假如我们新加入的边连接u和v,那么环的范围就是u-Lca(u,v)-v,所以我们就可以用rmq来解决求最大值这个问题。

#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
using namespace std;

const int maxl = 20;
int n,m,cur,head[800050],fa[800050][21],dep[800050],maxf[800050][21],vis[800020];
long long ans1,ans[800050];
struct tedge
{
    int nex,to,val,num,fro;
}e[805000];
struct data
{
    int u,v,c,num;
}p[800050];

void Add(int u,int v,int c,int num)
{
    cur++;  
    e[cur].to = v;
    e[cur].nex = head[u];
    e[cur].val = c;
    e[cur].num = num;
    e[cur].fro = u;
    head[u] = cur;
}

bool cmp(data a,data b)
{
    return (a.c<b.c||(a.c==b.c&&a.u<b.u));
}

int Find(int x)
{
    if (x==fa[x][0]) return x;
    fa[x][0] = Find(fa[x][0]);
    return fa[x][0];
}

void Make_fa()
{
    for (int i=1; i<=maxl; i++)
      for (int j=1; j<=n; j++)
      fa[j][i] = fa[fa[j][i-1]][i-1];
    for (int i=1; i<=maxl; i++)
      for (int j=1; j<=n; j++)
      maxf[j][i] = max(maxf[j][i-1],maxf[fa[j][i-1]][i-1]);
}

void dfs(int root,int f)
{
    dep[root] = dep[f]+1;
    for (int i=head[root]; i!=-1; i=e[i].nex)
    {
        int v = e[i].to;
        if (v==f) continue;
        if (vis[e[i].num]!=1) continue;
        fa[v][0] = root;
        maxf[v][0] = e[i].val;
        dfs(v,root);
    }
}

int Lca(int a,int b)
{
    int u=a,v=b,cnt=0;
    if (dep[u]<dep[v]) swap(u,v);
    for (int i=maxl; i>=0; i--)
    if (dep[fa[u][i]]>dep[v]) 
    {
        cnt = max(cnt,maxf[u][i]);
        u = fa[u][i];
    }
    if (dep[u]>dep[v])
    {
        cnt = max(cnt,maxf[u][0]);
        u = fa[u][0];
    }
    if (u==v) return cnt;
    for (int i=maxl; i>=0; i--)
    if (fa[u][i]!=fa[v][i])
    {
        cnt = max(cnt,maxf[u][i]);
        cnt = max(cnt,maxf[v][i]);
        u = fa[u][i];
        v = fa[v][i];
    }
    cnt = max(cnt,maxf[u][0]);
    cnt = max(cnt,maxf[v][0]);
    return cnt;
}

int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=0; i<=n; i++)
    head[i] = -1;
    for (int i=1; i<=m; i++)
    {
        int u,v,c;
        scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].c);
        p[i].num = i;
    }
    sort(p+1,p+1+m,cmp);
    for (int i=1; i<=m; i++)
    {
        Add(p[i].u,p[i].v,p[i].c,p[i].num);
        Add(p[i].v,p[i].u,p[i].c,p[i].num);
    }
    
    for (int i=1; i<=n; i++)
    fa[i][0] = i;
    for (int i=1; i<=cur; i++)
    {
        int u = Find(e[i].fro), v = Find(e[i].to);
        if (u==v) continue;
        ans1+=(long long)e[i].val;  vis[e[i].num] = 1;
        fa[v][0] = u;  fa[e[i].to][0] = u;
    }
    for (int i=1; i<=cur; i++)
    if (vis[e[i].num]==1) ans[e[i].num] = (long long)ans1;
    
    fa[1][0] = 0;  maxf[1][0] = 0;
    dfs(1,0);
    Make_fa();
    
    for (int i=1; i<=cur; i++)
    if (vis[e[i].num]!=1)
    {
        int maxe = 0;
        maxe = Lca(e[i].fro,e[i].to);
        ans[e[i].num] = (long long)ans1-maxe+e[i].val;
        i++;
    }
    
    for (int i=1; i<=m; i++)
    printf("%I64d\n",ans[i]);
    return 0;
}

 

posted @ 2017-09-18 21:58  最终惊吓者——Janous  阅读(242)  评论(0编辑  收藏  举报