【HDU 3938】Portal (并查集+离线)
http://acm.hdu.edu.cn/showproblem.php?pid=3938
两点之间建立传送门需要的能量为他们之间所有路径里最小的T,一条路径的T为该路径上最长的边的长度。现在 Q 个询问,问 L 能量可以选择多少种不同点对?
因为小的能量找出的点对,在大的能量下肯定也能建立传送门,因此把询问记下来,按询问的能量从小到大计算,这样离线处理。
从小到大枚举添加每条能量不超过当前能量且还没枚举过的边,
如果它连接的两个点属于不同联通块,就加上这条边。
能选择的点对就有两个联通块的点数之积那么多种。
#include <algorithm> #include <cstdio> #include <cstring> #define ll long long using namespace std; #define N 10005 struct edge{ int u,v,w; }e[N*5]; int cmp0(edge a, edge b){ return a.w<b.w; } struct question{ int id,v,ans; }q[N]; int cmp(question a,question b){ return a.v<b.v; } int cmp2(question a, question b){ return a.id<b.id; } int n,m,Q; int fa[N],num[N]; int find(int v){ int k,j,fv=v; while(fv!=fa[fv]) fv=fa[fv]; k=v; while(k!=fv){ j=fa[k]; fa[k]=fv; k=j; } return fv; } void init(){ for(int i=1;i<=n;i++) fa[i]=i,num[i]=1; } int main() { while(~scanf("%d%d%d",&n,&m,&Q)){ init(); for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); sort(e+1,e+1+m,cmp0); for(int i=1;i<=Q;i++){ scanf("%d",&q[i].v); q[i].id=i; q[i].ans=0; } sort(q+1,q+1+Q,cmp); int l=1; for(int i=1;i<=Q;i++){ q[i].ans=q[i-1].ans; for(;l<=m&&e[l].w<=q[i].v;l++){ int fu=find(e[l].u),fv=find(e[l].v); if(fu!=fv){ fa[fv]=fu; q[i].ans+=num[fu]*num[fv]; num[fu]+=num[fv]; } } } sort(q+1,q+1+Q,cmp2); for(int i=1;i<=Q;i++) printf("%d\n",q[i].ans); } return 0; }
┆凉┆暖┆降┆等┆幸┆我┆我┆里┆将┆ ┆可┆有┆谦┆戮┆那┆ ┆大┆始┆ ┆然┆
┆薄┆一┆临┆你┆的┆还┆没┆ ┆来┆ ┆是┆来┆逊┆没┆些┆ ┆雁┆终┆ ┆而┆
┆ ┆暖┆ ┆如┆地┆站┆有┆ ┆也┆ ┆我┆ ┆的┆有┆精┆ ┆也┆没┆ ┆你┆
┆ ┆这┆ ┆试┆方┆在┆逃┆ ┆会┆ ┆在┆ ┆清┆来┆准┆ ┆没┆有┆ ┆没┆
┆ ┆生┆ ┆探┆ ┆最┆避┆ ┆在┆ ┆这┆ ┆晨┆ ┆的┆ ┆有┆来┆ ┆有┆
┆ ┆之┆ ┆般┆ ┆不┆ ┆ ┆这┆ ┆里┆ ┆没┆ ┆杀┆ ┆来┆ ┆ ┆来┆