hdu Portal(离线,并查集)
题意:在一张无向图上,已知边权,做q组询问,问小于L的点对共有几组。点对间的距离取=min(两点之间每一条通路上的最大值)。
分析:这里取最大值的最小值,常用到二分。而这里利用离线算法,先对边从小到大排序,逐一加入集合中。利用并查集,当两点之间不在同一个集合,那么所加入的边就是两个集合中任一点对的距离(两集合各取一点)。所以有cnt2+=num[fu]*num[fv];
注意:有些询问比m条边中的最小边还小,比最大边还大。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int MAXN=11111; 7 8 struct Edge{ 9 int u,v,c; 10 }edge[5*MAXN]; 11 12 struct Query{ 13 int sq,id; 14 }query[MAXN]; 15 16 int num[MAXN],ans[MAXN]; 17 int f[MAXN]; 18 19 int cmp1(Edge a,Edge b) 20 { 21 return a.c<b.c; 22 } 23 24 int cmp2(Query a,Query b) 25 { 26 return a.sq<b.sq; 27 } 28 29 void init(int n) 30 { 31 for(int i=1;i<=n;i++) 32 { 33 num[i]=1; 34 f[i]=i; 35 } 36 } 37 38 int find(int x) 39 { 40 return f[x]==x?x:f[x]=find(f[x]); 41 } 42 43 int main() 44 { 45 int n,m,q; 46 while(~scanf("%d%d%d",&n,&m,&q)) 47 { 48 for(int i=0;i<m;i++) 49 scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].c); 50 sort(edge,edge+m,cmp1); 51 52 for(int i=0;i<q;i++) 53 { 54 scanf("%d",&query[i].sq); 55 query[i].id=i; 56 } 57 sort(query,query+q,cmp2); 58 59 init(n); 60 int cnt1,cnt2,tol=0; 61 cnt1=cnt2=0; 62 for(int i=0;i<m;i++) 63 { 64 int u=edge[i].u; 65 int v=edge[i].v; 66 int c=edge[i].c; 67 68 int fu=find(u); 69 int fv=find(v); 70 71 if(fu==fv)//在同一集合不影响 72 continue; 73 74 cnt1=cnt2;//记录上一个值 75 cnt2+=num[fu]*num[fv]; 76 77 f[fv]=fu; 78 num[fu]+=num[fv];//注意这两步处理要相同 79 80 while(c>query[tol].sq)//取cnt1更新询问 81 { 82 ans[query[tol].id]=cnt1; 83 tol++; 84 } 85 } 86 while(tol<q)//把大于最大边的询问统一处理成cnt2 87 { 88 ans[query[tol].id]=cnt2; 89 tol++; 90 } 91 for(int i=0;i<q;i++) 92 printf("%d\n",ans[i]); 93 } 94 return 0; 95 }