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\n",ans1,ans2); return 0; 40 }
20160613