1. 程式人生 > >hdu 3938 (離線並查集)

hdu 3938 (離線並查集)

turn 每一個 scanf cto memset cnblogs 鏈接 查詢 sta

鏈接:http://acm.split.hdu.edu.cn/showproblem.php?pid=3938

題意:給出 n個點,m條邊的無向圖,給出q次查詢,每次的查詢給出一個l,使得在l的範圍下,建盡可能多的邊,求問在建這些邊的情況下,有多少條路徑(任意兩點可到達的對數)

題解:離線的並查集,剛開始的時候,暴力模擬,在每個並查集裏邊計算路徑數目,果斷T。。。正解:離線並查集,將每個查詢保存起來,根據l排序,依次計算在每個l下可以有多少條路徑,累加到每一個l。

#include <stdio.h>
#include <algorithm>
#include <math.h>
#include 
<string.h> #include <vector> #include <queue> #include <map> #include <stack> #include <iostream> #define pi acos(-1.0) #define INF 0x3f3f3f3f using namespace std; #define ll long long const int maxn=50010; int n,m,q; int f[maxn],num[maxn]; struct edge { int u,v,w;
bool operator < (const edge tmp) const { return w<tmp.w; } }e[maxn]; struct node { int id,l; bool operator < (const node tmp) const { return l<tmp.l; } }nd[maxn]; int found(int x) { if(x!=f[x]) f[x]=found(f[x]); return f[x]; } int Merge(int
a,int b) { int fx=found(a),fy=found(b); if(fx==fy) return 0; //在集合中,已經計算過了 f[fx]=fy; int ans=num[fx]*num[fy]; num[fy]+=num[fx]; num[fx]=0; return ans; } int main() { //freopen("C:\\Users\\Administrator\\Desktop\\a.txt","r",stdin); //ios::sync_with_stdio(false); //freopen("C:\\Users\\Administrator\\Desktop\\b.txt","w",stdout); int ans[maxn]; while(scanf("%d%d%d",&n,&m,&q)!=EOF) { memset(ans,0,sizeof ans); for(int i=0;i<m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); for(int i=0;i<q;i++) { scanf("%d",&nd[i].l); nd[i].id=i; } sort(e,e+m); sort(nd,nd+q); for(int i=0;i<=n;i++) num[i]=1,f[i]=i; int pos=0,tmp=0; for(int i=0;i<q;i++) { while(pos<m&&nd[i].l>=e[pos].w) { tmp+=Merge(e[pos].u,e[pos].v); pos++; } ans[nd[i].id]=tmp; } for(int i=0;i<q;i++) printf("%d\n",ans[i]); } return 0; }

hdu 3938 (離線並查集)