[Lydsy2017省队十连测]公路建设
SOL:
我们发现一棵生成树最多99条边,用线段树合并。
#include<bits/stdc++.h> #define Mid (l+r>>1) #define ls no<<1,l,Mid #define rs no<<1|1,Mid+1,r #define N 110009 using namespace std; struct Edge{ int l,r,co; }e[N]; int f[107]; struct Node{ int sum,a[107],to; void clear() { memset(a,0,sizeof a); sum=0; to=0; } int fa(int x){ return f[x]==x?x:f[x]=fa(f[x]); } inline void join(int xx){ static int u,v; u=fa(e[xx].l); v=fa(e[xx].r); if (u==v) return; a[++to]=xx; f[u]=v; sum+=e[xx].co; } void merge(Node X,Node& Y){ static int ti,tj,op; clear(); for (int i=1;i<107;i++) f[i]=i; ti=1; tj=1; while (X.a[ti]&&Y.a[tj]) if (e[X.a[ti]].co<e[Y.a[tj]].co) join(X.a[ti++]); else join(Y.a[tj++]); while (X.a[ti]) join(X.a[ti++]); while (Y.a[tj]) join(Y.a[tj++]); } }t[N<<2],Ans; void build(int no,int l,int r){ if (l==r) { t[no].sum=e[l].co; t[no].a[1]=l; return; } build(no<<1,l,Mid); build(no<<1|1,Mid+1,r); t[no].merge(t[no<<1],t[no<<1|1]); } #define sight(x) ('0'<=x&&x<='9') inline void read(int &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);} inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); } inline void writel(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); } void que(int no,int l,int r,int L,int R){ if (L<=l&&r<=R) { Ans.merge(Ans,t[no]); return; } if (L<=Mid) que(no<<1,l,Mid,L,R); if (R> Mid) que(no<<1|1,Mid+1,r,L,R); } int n,m,q,l,r; signed main () { read(n); read(m); read(q); for (int i=1;i<=m;i++) read(e[i].l),read(e[i].r),read(e[i].co); build(1,1,m); while (q--) { read(l); read(r); Ans.clear(); que(1,1,m,l,r); writeln(Ans.sum); } return 0; }