hdu4750(离线并查集+思路)
题意:
n个点,m条边的无向图,每条边a b c,点a到点b的权值是c。
p(0<p<=100000)个人,以下p行每行有一个值t,找出有多少对点(i, j)满足f大于等于t。
f值的定义:从i点到j点,有好几种走法,每种走法中取路径中权值最大的边值,所有走法中的值中,取最小的那个即为f值
//#pragma comment(linker, "/STACK:102400000") #include<cstdlib> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> #include<list> #include<queue> #include<vector> #define tree int o,int l,int r #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define lo o<<1 #define ro o<<1|1 #define ULL unsigned long long #define LL long long #define inf 0x7fffffff #define eps 1e-7 #define N 10005 #define M 500009 using namespace std; int m,n,T,t,x,y,u,qn; struct Node { int x,y,val; bool operator<(const Node a)const { return val<a.val; } } node[M]; int q[M/5+100],f[M/5+100],ans[M/5+100]; int s[N],cnt[N]; bool cmp(int a,int b) { return q[a]<q[b]; } int find(int x) { return x==s[x]?x:s[x]=find(s[x]); } int main() { #ifndef ONLINE_JUDGE freopen("ex.in","r",stdin); #endif // scanf("%d",&T); // while(T--) int ncase=0; while(scanf("%d%d",&n,&m)==2) { for(int i=0; i<m; ++i) scanf("%d%d%d",&node[i].x,&node[i].y,&node[i].val); sort(node,node+m); scanf("%d",&qn); for(int i=0; i<qn; i++) { scanf("%d",&q[i]); f[i]=i; } sort(f,f+qn,cmp); for(int i=0; i<=n; i++) { s[i]=i; cnt[i]=1; } int tp=0,j=0; for(int i=0; i<qn; i++) { int sub=f[i]; while(j<m&&node[j].val<q[sub]) { int u=node[j].x,v=node[j].y; int toux=find(u); int touy=find(v); if(toux!=touy) { tp+=cnt[touy]*cnt[toux]; s[touy]=toux; cnt[toux]+=cnt[touy]; } j++; } ans[sub]=tp; } while(j<m)//WA,求tp { int u=node[j].x,v=node[j].y; int toux=find(u); int touy=find(v); if(toux!=touy) { tp+=cnt[touy]*cnt[toux]; s[touy]=toux; cnt[toux]+=cnt[touy]; } j++; } for(int i=0; i<qn; i++) printf("%d\n",(tp-ans[i])*2); } return 0; }