[并查集]JZOJ 4223 旅游
分析
这道题其实非常简单,把询问混进边里排序就行了,用并查集维护图的连通性,合并的时候加一下答案,用个size数组
#include <iostream> #include <cstdio> #include <algorithm> #include <memory.h> using namespace std; const int N=2e4+10; struct Edge { int u,v,w,nx,id,ans; }g[10*N]; int cnt,list[N]; int sz[N],f[N]; int t,n,m,q; void Add(int u,int v,int w) { g[++cnt]=(Edge){u,v,w,list[u]};list[u]=cnt; } int Get_F(int x) {return f[x]==x?x:f[x]=Get_F(f[x]);} bool CMP(Edge a,Edge b) {return a.w<b.w||a.w==b.w&&a.u>b.u;} bool CMP_(Edge a,Edge b) {return a.id>b.id;} int main() { for (scanf("%d",&t);t;t--) { scanf("%d%d%d",&n,&m,&q); cnt=0;memset(list,0,sizeof list); for (int i=1,u,v,w;i<=m;i++) scanf("%d%d%d",&u,&v,&w),Add(u,v,w); for (int i=1;i<=q;i++) cnt++,scanf("%d",&g[cnt].w),g[cnt].u=g[cnt].v=-1,g[cnt].id=i; sort(g+1,g+cnt+1,CMP); for (int i=1;i<=n;i++) f[i]=i,sz[i]=1; int ans=0; for (int i=1;i<=cnt;i++) if (g[i].u!=-1) { int fu=Get_F(g[i].u),fv=Get_F(g[i].v); if (fu==fv) continue; ans+=sz[fu]*sz[fv]*2;sz[fu]+=sz[fv];f[fv]=fu; } else g[i].ans=ans; sort(g+1,g+cnt+1,CMP_); for (int i=q;i;i--) printf("%d\n",g[i].ans); } }
在日渐沉没的世界里,我发现了你。