[SCOI2012]滑雪

2021.1.29

Solution

很早之前做过的题……今天又考,还很脑瘫地做错了……但发现之前并没有完全理解,所以还是写一下

先考虑问题一,求最多能到多少个点。容易知道只要存在一条通路,就一定能到,且后面算费用的时候该点一定能被算到。所以直接从 1 开始 bfs,统计能到的点个数。

问题二。将能到的所有点和所有边建成新图 (G')。再在该新图上求最小生成树。和常规的生成树不同,该图的边存在有向边,这会影响图的连通性。即如果连了一条边 (u o v)(v)(u) 并不是连通的,然而并查集并不能区分这种差异,这就会造成最后求出的生成树不连通的问题。我们需要对 Kruskal 进行改造,将排序时加入以终点高度为第一关键字降序排,长度为第二关键字升序排。考虑这样的正确性。如果当前正在处理终点高度为 (H) 的边的话,那么高度大于 (H) 的点一定已经处理好了,并且一定是和 (1) 连通的。把这条边加上后,构造出的生成树也一定连通。

#include<stdio.h>
#include<queue>
#include<algorithm>
using namespace std;
#define rint register int 
#define ll long long
#define N 200007
#define M N*10

template<class T>
inline void read(T &x){
    x=0;char c=getchar();T flag=1;
    while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    x*=flag;
}

int n,m,X[M],Y[M],ans1=0,fa[N],cnt=0,_cnt=0,head[N],_head[N];
ll dis[M],h[N],ans2=0;
bool vis[N];

struct E{
    int next,to,rk;
    ll dis;
}e[M],_e[M];
queue<int> Q;

inline bool Cmp(const E a,const E b){
    if(h[a.to]!=h[b.to]) return h[a.to]>h[b.to];
    return a.dis<b.dis;
}

inline int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}

inline void add_(int id,int to,ll dis,int rk){
    _e[++_cnt]=(E){_head[id],to,rk,dis};
    _head[id]=_cnt;
}

inline void add(int id,int to,ll dis,int rk){
    e[++cnt]=(E){head[id],to,rk,dis};
    head[id]=cnt;
}

inline void bfs(){
    Q.push(1);vis[1]=true;ans1++;
    while(!Q.empty()){
        int u=Q.front();Q.pop();
        for(rint i=_head[u];i;i=_e[i].next){
            int v=_e[i].to;
            add(u,v,_e[i].dis,_e[i].rk);
            if(!vis[v]){
                vis[v]=true;ans1++;
                Q.push(v);
            }
        }
    }
}

int main(){
    freopen("irrigation.in","r",stdin);
    freopen("irrigation.out","w",stdout); 
    read(n);read(m);
    for(rint i=1;i<=n;++i) read(h[i]),fa[i]=i;
    for(rint i=1;i<=m;++i){
        read(X[i]);read(Y[i]);read(dis[i]);
        if(h[X[i]]>=h[Y[i]]) add_(X[i],Y[i],dis[i],i);
        if(h[X[i]]<=h[Y[i]]) add_(Y[i],X[i],dis[i],i);
    }
    bfs();
    sort(e+1,e+1+cnt,Cmp);
    rint k,u,v;
    for(rint i=1;i<=cnt;++i){
        k=e[i].rk;
        u=X[k],v=Y[k];
        if((!vis[u])||(!vis[v])) continue;
        u=find(u),v=find(v);
        if(u==v) continue;
        fa[u]=v;ans2+=dis[k];
    }
    printf("%d %lld",ans1,ans2);
}
原文地址:https://www.cnblogs.com/wwlwQWQ/p/14346795.html