HDU-3938 Portal (并查集+离线输出)
2015-03-09 13:59
337 查看
这也是作业啊,可惜题目都看不懂,然后就果断看题解了。
因为考虑到数据的情况,如果输入一次做一次计算,然后输出,10000组数据会TLE呢,所以就看了题解的离线输出。
先在que的结构体中设置一个L,和一个id,先按照L排序,按顺序算出答案,最后再按照初始的id排序输出答案。
题目给了很多边,然后要求花费小于等于L的两个节点对的数量。花费的定义是,两个节点中有n条路,每条路是由几条边连成的,每条路中最大的边就是这条路的花费,然后两个节点间的花费就是这n条路中的花费的最小值。
这题的思路是先用kruskal合并路线,然后开个sum数组记录每个父节点所在集合的点的数量。
然后思想是如果两个节点已经在同一个集合中了,那么这条边就不取。why?因为kruskal是按照边权排序的,如果两个点在一个集合中,说明它们之间已经连通了,有路径了,并且那条路径的花费小于当前考虑的路径的花费,所以不取。
如果两个节点分别在A,B两个集合中,A中有sum[A]个点,B中有sum[B]个点,那么A中的点到B中的点都连通了,然后A中一点到B中一点有一条路径,这条路径的花费肯定是当前考察的edge(因为花费是路径中的最大值,而edge是按照权值排序的)。这样一下子就增加了sum[A]*sum[B]条路。
其实这题就离线输出这个坑点还有就是sum存储的要点,也是不难的。我仍需努力啊
因为考虑到数据的情况,如果输入一次做一次计算,然后输出,10000组数据会TLE呢,所以就看了题解的离线输出。
先在que的结构体中设置一个L,和一个id,先按照L排序,按顺序算出答案,最后再按照初始的id排序输出答案。
题目给了很多边,然后要求花费小于等于L的两个节点对的数量。花费的定义是,两个节点中有n条路,每条路是由几条边连成的,每条路中最大的边就是这条路的花费,然后两个节点间的花费就是这n条路中的花费的最小值。
这题的思路是先用kruskal合并路线,然后开个sum数组记录每个父节点所在集合的点的数量。
然后思想是如果两个节点已经在同一个集合中了,那么这条边就不取。why?因为kruskal是按照边权排序的,如果两个点在一个集合中,说明它们之间已经连通了,有路径了,并且那条路径的花费小于当前考虑的路径的花费,所以不取。
如果两个节点分别在A,B两个集合中,A中有sum[A]个点,B中有sum[B]个点,那么A中的点到B中的点都连通了,然后A中一点到B中一点有一条路径,这条路径的花费肯定是当前考察的edge(因为花费是路径中的最大值,而edge是按照权值排序的)。这样一下子就增加了sum[A]*sum[B]条路。
其实这题就离线输出这个坑点还有就是sum存储的要点,也是不难的。我仍需努力啊
#include<iostream> #include<cstdio> #include<cctype> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #include<string> #include<vector> #include<queue> #include<map> #include<set> #include<sstream> #include<stack> using namespace std; #define MAX 10000+5 #define MAXN 50000+5 typedef long long LL; const double pi=3.141592653589793; const int INF=1e9; const double inf=1e20; const double eps=1e-10; const int mod=1000000007; int pre[MAX]; int sum[MAX];//记录父节点所在的集合中的点的数量 struct E{ int u,v,de; }edge[MAXN]; struct Q{ int l,id,ans;//离线输出,所以先要按照l排序算出所有答案,然后按照id排序进行输出 }que[MAX]; bool cmp(struct E a,struct E b){ return a.de<b.de; } bool cmp1(struct Q a,struct Q b){ return a.l<b.l; } bool cmp2(struct Q a,struct Q b){ return a.id<b.id; } int Find(int x){ return pre[x]==x?x:pre[x]=Find(pre[x]); } int Union(int a,int b){ int fx=Find(a); int fy=Find(b); int temp; if(fx==fy) return 0;//如果两个点在同一个集合中,他们之间有其他路径,其他路径中的最长边肯定小于edge[a][b]; pre[fx]=fy;//fy为fx集合的父节点 temp=sum[fx]*sum[fy];//两个集合相连,从一个fx集合的点到fy集合的点总共有sum[fx]*sum[fy]条路径,这些路径中最长值都是edge[a][b] sum[fy]+=sum[fx];//更新父节点集合中的点的数量 return temp; } int main(){ int n,m,q; while(~scanf("%d%d%d",&n,&m,&q)){ for(int i=1;i<=n;i++){ pre[i]=i; sum[i]=1; } for(int i=0;i<m;i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].de); for(int i=0;i<q;i++){ scanf("%d",&que[i].l); que[i].id=i; que[i].ans=0; } sort(edge,edge+m,cmp); sort(que,que+q,cmp1); int cnt=0; for(int i=0;i<q;i++){ while(edge[cnt].de<=que[i].l&&cnt<m){ que[i].ans+=Union(edge[cnt].u,edge[cnt].v); cnt++; } if(i) que[i].ans+=que[i-1].ans;//l大的que肯定包括l小的que的解 } sort(que,que+q,cmp2); for(int i=0;i<q;i++) printf("%d\n",que[i].ans); } return 0; }
相关文章推荐
- 多校第十场 HDU 3938 Portal(离线的并查集)
- hdu 3938 Portal 计算两点路上最大距离中的最小值<=L的路径个数 离线并查集
- hdu 3938 Portal离线并查集
- HDU-3938 Portal 克鲁斯卡尔思想 (离线并查集)
- hdu 3938 Portal(离线并查集)
- hdu 3938 Portal(离线并查集)
- hdu-3938 Portal 离线最小生成树
- HDU 3938 Portal【并查集+upper_bound(第四个参数)】
- hdu 3938 Portal
- HDU 3938 Portal
- 【HDU 3938】Portal (并查集+离线)
- hdu 3938 Portal
- hdu 3938 Portal
- HDU 3938 Portal(离线+Kruskal+并查集)
- HDOJ 3938 Portal (离线并查集)
- hdu-3938-Portal-并查集
- hdu 3938(离线并查集)
- HDU 4750 && HDU 3938 离线并查集
- hdu 3938 Portal (prim+离线)
- hdu 3938 Portal