USACO2002-OPEN-GREEN(GREEN秘密的牛奶管道SECRET)

约翰叔叔希望能够廉价连接他的供水系统,但是他不希望他的竞争对手知道他选择的路线。一般这样的问题需要选择最便宜的方式,所以他决定避免这种情况而采用第二便宜的方式。
现在有W(3 <= W <= 2000)个供水站,其中最多有P(P <=20,000)条管道,每一条管道连接了两个水站,并且不存在一条管道连接同一个水站,两个水站之间最多只有一条管道。每条管道有一定的费用。请寻找第二便宜的连接方式,使所有的水站相连。
假设最便宜的方案有且只有一种,并且至少有两种可行的连接方案。所有的费用都不超过16位有符号整数。水站用1到W的自然数表示
输入
第一行:两个数W和P 第2~P+1行:每行描述了一条管道,有3个用空格分开的整数,前两个数表示管道连接的两个端点。第3个数是管道的费用
输出
仅一行,第二便宜的管道铺设费用
样例输入
5 7
1 2 3
2 3 4
1 4 7
2 4 11
2 5 9
5 4 5
3 5 8
样例输出
20

这不就是最小生成树板子吗?

而且还不需要严格小

那不就是水题了吗?

#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    return res;
}
int n,m,cnt,s,minn=1e9,fa[100005],f[100005][20],d1[100005][20],d2[100005][20],adj[100005],nxt[600005],to[600005],val[600005],dep[100005];
ll ans;
struct edge{
    int u,v,len,vis;
}e[300005];
inline void addedge(int u,int v,int w){
    nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
    nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u,val[cnt]=w;
}
inline bool cmp(edge a,edge b){
    return a.len<b.len;
}
inline int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void dfs(int point,int fa)
{
    for(int i=1;i<=16;i++)
      if(dep[point] >= 1<<i)
      {
        f[point][i] = f[f[point][i-1]][i-1];
        d1[point][i] = max(d1[point][i-1] , d1[f[point][i-1]][i-1]);
      }
      else break;
    for(int u=adj[point];u;u=nxt[u])
    {
      int e=to[u];
      if(e == fa) continue;
      f[e][0] = point;
      dep[e] = dep[point] + 1;
      d1[e][0] = val[u];
      dfs(e,point);
    }
}
inline int lca(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    int del=dep[x]-dep[y];
    for(int i=17;i>=0;i--){
        if(del>=(1<<i)) del-=(1<<i),x=f[x][i];
    }
    if(x==y) return x;
    for(int i=17;i>=0;i--){
        if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    }
    return f[x][0];
}
inline void search(int u,int fa,int len){
    int max1=0,del=dep[u]-dep[fa];
    for(int i=17;i>=0;i--){
        if(del>=(1<<i)){
            del-=1<<i;
            if(d1[u][i]>max1)max1=d1[u][i];
            u=f[u][i];
        }
    }
    minn=min(minn,len-max1);
}
inline void solve(int x,int y,int z){
    int g=lca(x,y);
    search(x,g,z),search(y,g,z);
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++){
        e[i].u=read(),e[i].v=read(),e[i].len=read();
    }
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++){
        int f1=find(e[i].u),f2=find(e[i].v);
        if(f1!=f2){
            ans+=e[i].len;
            fa[f1]=f2;
            e[i].vis=1;
            addedge(e[i].u,e[i].v,e[i].len);
            s++;
            if(s==n-1)break;
        }
    }
    dfs(1,0);
    for(int i=1;i<=m;i++){
        if(!e[i].vis) solve(e[i].u,e[i].v,e[i].len);
    }
    cout<<ans+minn<<'\n';
}
posted @ 2018-10-18 15:46  Stargazer_cykoi  阅读(199)  评论(0编辑  收藏  举报