題意:定義T是2點間某條路徑上的最大邊權,要找出某兩點間所有路徑上的T的最小值,給定一個L問,滿足小於等於L的min{T}的個數
題出的挺坑爹的,讀半天沒讀懂啥意思。
達哥說是離線的並查集,大概就是用並查集來維護圖,根據邊權從小到大不斷往圖中加邊,新加的邊一定滿足是2點間的某路徑的最大值,若2點本身不在同一連通分量上,則這條邊就是所求的minT,滿足它的個數就是2個連通分量的定點個數的乘積。
#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int maxq=10100;const int maxn=10100;const int maxm=50500;int p[maxn],rank[maxn],cnt[maxn];//for merge-find setsint index[maxq] , que[maxq] , ans[maxq];//for queryint ind[maxm] ;//for edgestruct Edge{ int u,v,w;}edge[maxm];int find (int x){ return p[x]==x?x:p[x]=find(p[x]);}int merge (int a,int b){ int fa=find (a); int fb=find (b); if(fa==fb)return 0; int t=cnt[fa]*cnt[fb]; if(rank[fa]>rank[fb])p[fb]=fa,cnt[fa]+=cnt[fb],cnt[fb]=0; else p[fa]=fb,cnt[fb]+=cnt[fa],cnt[fa]=0; if(rank[fa]==rank[fb])rank[fb]++; return t;}bool cmp1 (int a,int b){ return edge[a].w<edge[b].w;}bool cmp2 (int a, int b){ return que[a]<que[b];}int main (){ int n,m,q; int u,v,w; freopen ("in.in","r",stdin); freopen ("out.txt","w",stdout); while (~scanf("%d%d%d", &n,&m,&q)) { for (int i=0 ; i<m ; ++i) { scanf("%d%d%d",&u,&v,&w); u--,v--; edge[i].u=u;edge[i].v=v;edge[i].w=w; ind[i]=i; } for (int i=0 ; i<q ; ++i) { scanf("%d",que+i); index[i]=i; } for (int i=0 ; i<n ; ++i) rank[i]=0,p[i]=i,cnt[i]=1; //memset (ans , 0 ,sizeof(ans)); int tmp=0; sort (ind , ind+m , cmp1); sort (index , index+q , cmp2); for (int i=0 ,j=0; i<q ; ++i) { while (edge[ind[j]].w<=que[index[i]] && j<m) { tmp+=merge(edge[ind[j]].u,edge[ind[j]].v); ++j; } ans[index[i]]=tmp; } for (int i=0 ; i<q ; ++i) printf("%d\n",ans[i]); } return 0;}