一个很显然的思路是把边按时间段拆开线段树分治一下,用lct维护MST。理论上复杂度是O((M+Q)logNlogQ),实际常数爆炸T成狗。正解写不动了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<vector> #include<stack> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 20010 #define M 50010 #define lson tree[k].ch[0] #define rson tree[k].ch[1] #define lself tree[tree[k].fa].ch[0] #define rself tree[tree[k].fa].ch[1] int n,m,q,f[M],L[M<<2],R[M<<2],cnt; long long tot=0,ans[M]; struct edge{int x,y,z; }e[M],a[N+M<<1]; struct data{int i,x;}; vector<data> Q[M]; vector<int> tree[M<<2]; stack<int> undo[M<<2]; namespace lct { struct data{int ch[2],fa,rev,x;}tree[N+M<<1]; void up(int k) { tree[k].x=k; if (a[tree[lson].x].z>a[tree[k].x].z) tree[k].x=tree[lson].x; if (a[tree[rson].x].z>a[tree[k].x].z) tree[k].x=tree[rson].x; } void rev(int k){if (k) swap(lson,rson),tree[k].rev^=1;} void down(int k){if (tree[k].rev) rev(lson),rev(rson),tree[k].rev=0;} bool isroot(int k){return lself!=k&&rself!=k;} int whichson(int k){return rself==k;} void push(int k){if (!isroot(k)) push(tree[k].fa);down(k);} void move(int k) { int fa=tree[k].fa,gf=tree[fa].fa,p=whichson(k); if (!isroot(fa)) tree[gf].ch[whichson(fa)]=k;tree[k].fa=gf; tree[fa].ch[p]=tree[k].ch[!p],tree[tree[k].ch[!p]].fa=fa; tree[fa].fa=k,tree[k].ch[!p]=fa; up(fa),up(k); } void splay(int k) { push(k); while (!isroot(k)) { int fa=tree[k].fa; if (!isroot(fa)) if (whichson(fa)^whichson(k)) move(k); else move(fa); move(k); } } void access(int k){for (int t=0;k;t=k,k=tree[k].fa) splay(k),tree[k].ch[1]=t,up(k);} void makeroot(int k){access(k),splay(k),rev(k);} int findroot(int k){access(k),splay(k);for (;lson;k=lson) down(k);splay(k);return k;} void link(int x,int y){makeroot(x);tree[x].fa=y;} void cut(int x,int y){makeroot(x),access(y),splay(y);tree[y].ch[0]=tree[x].fa=0;up(y);} int query(int x,int y){makeroot(x),access(y),splay(y);return tree[y].x;} void newpoint(int k){tot+=a[k].z;link(k,a[k].x),link(k,a[k].y);} void delpoint(int k){tot-=a[k].z;cut(k,a[k].x),cut(k,a[k].y);} } void build(int k,int l,int r) { L[k]=l,R[k]=r; if (l==r) return; int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void add(int k,int l,int r,int e) { if (L[k]==l&&R[k]==r) {tree[k].push_back(e);return;} int mid=L[k]+R[k]>>1; if (r<=mid) add(k<<1,l,r,e); else if (l>mid) add(k<<1|1,l,r,e); else add(k<<1,l,mid,e),add(k<<1|1,mid+1,r,e); } void solve(int k) { int s=tree[k].size(); for (int i=0;i<s;i++) if (lct::findroot(a[tree[k][i]].x)!=lct::findroot(a[tree[k][i]].y)) lct::newpoint(tree[k][i]),undo[k].push(tree[k][i]); else { int t=lct::query(a[tree[k][i]].x,a[tree[k][i]].y); if (a[t].z>a[tree[k][i]].z) { lct::delpoint(t),lct::newpoint(tree[k][i]); undo[k].push(-t),undo[k].push(tree[k][i]); } } if (L[k]==R[k]) ans[L[k]]=tot; else solve(k<<1),solve(k<<1|1); while (!undo[k].empty()) { if (undo[k].top()<0) lct::newpoint(-undo[k].top()); else lct::delpoint(undo[k].top()); undo[k].pop(); } } int main() { freopen("bzoj2001.in","r",stdin); freopen("bzoj2001.out","w",stdout); n=read(),m=read(),q=read(); for (int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].z=read(); for (int i=1;i<=q;i++) { int x=read(),y=read(); Q[x].push_back((data){i,y}); } build(1,1,q); cnt=n; for (int i=1;i<=m;i++) { int s=Q[i].size(); if (s==0) a[++cnt]=e[i],add(1,1,q,cnt); else { if (Q[i][0].i>1) a[++cnt]=e[i],add(1,1,Q[i][0].i-1,cnt); for (int j=0;j<s-1;j++) a[++cnt]=(edge){e[i].x,e[i].y,Q[i][j].x}, add(1,Q[i][j].i,Q[i][j+1].i-1,cnt); a[++cnt]=(edge){e[i].x,e[i].y,Q[i][s-1].x}, add(1,Q[i][s-1].i,q,cnt); } } solve(1); for (int i=1;i<=q;i++) printf("%lld ",ans[i]); fclose(stdin);fclose(stdout); return 0; }