[SCOI2012]滑雪与时间胶囊
题目大意:
给你一个带边权图,每个点都有自己的高度h[i],结点只能通过边到达高度不高于它的结点j。
你可以通过某种手段跳转到你原来走过的结点,不计入路径。
问你从1号点出发,最多可以到达多少点?路径和最小是多少?
思路:
对于第一问,我们可以bfs一边把所有能走到的地方遍历一遍。
对于第二问,实际上就是在上一问遍历的点中找一个最小树形图。
如果我们把这些结点按照高度分成很多“层”,那么我们需要首先保证高的点连了边(后面低的就算不连边也可以从高的跳转过去)。
所以我们对于边集,先按照高度从大到小排序,再按照边权升序排序,跑一边Kruskal即可。
1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<cstring> 5 #include<algorithm> 6 typedef long long int64; 7 inline int getint() { 8 register char ch; 9 while(!isdigit(ch=getchar())); 10 register int x=ch^'0'; 11 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 12 return x; 13 } 14 const int N=100001,M=2000001; 15 int h[N]; 16 struct Edge { 17 int from,to,w,next; 18 bool operator < (const Edge &another) const { 19 if(h[to]==h[another.to]) return w<another.w; 20 return h[to]>h[another.to]; 21 } 22 }; 23 Edge e[M]; 24 int head[N],cnt; 25 inline void add_edge(const int &u,const int &v,const int &w) { 26 e[cnt]=(Edge){u,v,w,head[u]}; 27 head[u]=cnt++; 28 } 29 int ans1; 30 bool vis[N]; 31 inline void bfs() { 32 static std::queue<int> q; 33 q.push(1); 34 vis[1]=true; 35 while(!q.empty()) { 36 const int x=q.front(); 37 q.pop(); 38 ans1++; 39 for(register int i=head[x];~i;i=e[i].next) { 40 const int &y=e[i].to; 41 if(vis[y]) continue; 42 vis[y]=true; 43 q.push(y); 44 } 45 } 46 } 47 class DisjointSet { 48 private: 49 int anc[N]; 50 int find(const int &x) { 51 return x==anc[x]?x:anc[x]=find(anc[x]); 52 } 53 public: 54 DisjointSet() { 55 for(register int i=1;i<N;i++) { 56 anc[i]=i; 57 } 58 } 59 void Union(const int &x,const int &y) { 60 anc[find(x)]=find(y); 61 } 62 bool isConnected(const int &x,const int &y) { 63 return find(x)==find(y); 64 } 65 }; 66 DisjointSet s; 67 int main() { 68 const int n=getint(),m=getint(); 69 for(register int i=1;i<=n;i++) { 70 h[i]=getint(); 71 } 72 memset(head,-1,sizeof head); 73 for(register int i=1;i<=m;i++) { 74 const int u=getint(),v=getint(),w=getint(); 75 if(h[u]>=h[v]) add_edge(u,v,w); 76 if(h[v]>=h[u]) add_edge(v,u,w); 77 } 78 bfs(); 79 std::sort(&e[0],&e[cnt]); 80 int64 ans2=0; 81 for(register int i=0;i<cnt;i++) { 82 const int &u=e[i].from,&v=e[i].to,&w=e[i].w; 83 if(!vis[u]||!vis[v]) continue; 84 if(s.isConnected(u,v)) continue; 85 s.Union(u,v); 86 ans2+=w; 87 } 88 printf("%d %lld\n",ans1,ans2); 89 return 0; 90 }