bzoj2753[SCOI2012]滑雪与时间胶囊

bzoj2753[SCOI2012]滑雪与时间胶囊

题意:

n点m有权边图,每个点都有高度,只能从高度高的点到高度低的点。同时还可以瞬移到走过的点,希望求经过最多点的最短时间。n≤100000,m≤1000000。

题解:

第一问:用bfs扩展出能到达的所有点,并标记。第二问:分层做最小生成树。最后一个问题:怎么分层呢?其实很简单,最小生成树之前要把边排序,这个时候我们把高度作为第一关键字,然后高度相同再按照边权排序,这样就分层了啊

感觉很神的样子。反思:因为边数弄错wa了好几发QAQ~

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define maxn 100500
 7 #define ll long long
 8 using namespace std;
 9 
10 struct e{int f,t; ll w; int n;}; e es[maxn*20]; int g[maxn],ess,h[maxn];
11 void pe(int f,int t,ll w){es[++ess]=(e){f,t,w,g[f]}; g[f]=ess;}
12 bool cmp(e a,e b){return h[a.t]!=h[b.t]?h[a.t]>h[b.t]:a.w<b.w;}
13 inline int read(){
14     char ch=getchar(); int f=1,x=0;
15     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
16     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
17     return f*x;
18 }
19 bool vis[maxn]; queue <int> q; int n,m,ans1,fa[maxn],tot; ll ans2;
20 void bfs(int s){
21     while(!q.empty())q.pop(); memset(vis,0,sizeof(vis)); q.push(s); vis[s]=1; ans1=1;
22     while(! q.empty()){
23         int x=q.front(); q.pop();
24         for(int i=g[x];i;i=es[i].n)if(!vis[es[i].t])vis[es[i].t]=1,q.push(es[i].t),ans1++;
25     }
26 }
27 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
28 int main(){
29     n=read(); m=read(); inc(i,1,n)h[i]=read();
30     inc(i,1,m){
31         int a=read(),b=read(); ll c=(ll)read();
32         if(h[a]>=h[b])pe(a,b,c); if(h[a]<=h[b])pe(b,a,c);
33     }
34     bfs(1); sort(es+1,es+ess+1,cmp); inc(i,1,n)fa[i]=i; ans2=tot=0;
35     inc(i,1,ess){
36         int x=find(es[i].f),y=find(es[i].t); if(!vis[es[i].f]||!vis[es[i].t]||x==y)continue;
37         fa[x]=y; tot++; ans2+=es[i].w; if(tot==ans1-1)break;
38     }
39     printf("%d %lld
",ans1,ans2); return 0;
40 }

20160613

原文地址:https://www.cnblogs.com/YuanZiming/p/5779833.html