BZOJ4046 : [Cerc2014] Pork barre
按边权从大到小加边,用Link-Cut Tree维护最小生成树。
对于当前要加的边i,最小生成树上边权在[1,R]范围内的和就是询问[e[i].w,R]的答案。
因为强制在线,所以用主席树存下所有历史版本即可。时间复杂度$O(n\log n)$。
#include<cstdio> #include<algorithm> using namespace std; const int N=101010,M=3600010; struct edge{int x,y,w;}e[N]; inline bool cmp(edge a,edge b){return a.w>b.w;} int T,n,m,q,i,j,x,y,ans,root[N],l[M],r[M],v[M],tot; int f[N],son[N][2],val[N],sum[N],from[N],tmp[N],fa[N];bool rev[N]; int ins(int x,int a,int b,int c,int d){ int y=++tot; v[y]=v[x]+d,l[y]=l[x],r[y]=r[x]; if(a==b)return y; int mid=(a+b)>>1; if(c<=mid)l[y]=ins(l[x],a,mid,c,d);else r[y]=ins(r[x],mid+1,b,c,d); return y; } int ask(int x,int a,int b,int c,int d){ if(!x||c>d)return 0; if(c<=a&&b<=d)return v[x]; int mid=(a+b)>>1,t=0; if(c<=mid)t=ask(l[x],a,mid,c,d); if(d>mid)t+=ask(r[x],mid+1,b,c,d); return t; } inline bool isroot(int x){return !f[x]||(son[f[x]][0]!=x&&son[f[x]][1]!=x);} inline void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;} inline void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;} inline void up(int x){ sum[x]=val[x],from[x]=x; if(son[x][0])if(sum[son[x][0]]>sum[x])sum[x]=sum[son[x][0]],from[x]=from[son[x][0]]; if(son[x][1])if(sum[son[x][1]]>sum[x])sum[x]=sum[son[x][1]],from[x]=from[son[x][1]]; } inline void rotate(int x){ int y=f[x],w=son[y][1]==x; son[y][w]=son[x][w^1]; if(son[x][w^1])f[son[x][w^1]]=y; if(f[y]){ int z=f[y]; if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x; } f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y); } inline void splay(int x){ int s=1,i=x,y;tmp[1]=i; while(!isroot(i))tmp[++s]=i=f[i]; while(s)pb(tmp[s--]); while(!isroot(x)){ y=f[x]; if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);} rotate(x); } up(x); } inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);} inline void makeroot(int x){access(x);splay(x);rev1(x);} inline void link(int x,int y){makeroot(x);f[x]=y;access(x);} inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);} inline void cut(int x,int y){makeroot(x);cutf(y);} inline int askfrom(int x,int y){makeroot(x);access(y);splay(y);return from[y];} int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);} inline int lower(int x){ int l=1,r=m,mid,t=0; while(l<=r)if(e[mid=(l+r)>>1].w<=x)r=(t=mid)-1;else l=mid+1; return t; } inline int getid(int x){ int l=1,r=m,mid,t=0; while(l<=r)if(e[mid=(l+r)>>1].w>=x)l=(t=mid)+1;else r=mid-1; return t; } inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} int main(){ read(T); while(T--){ read(n),read(m); for(i=1;i<=n;i++)fa[i]=i; for(i=1;i<=m;i++)read(e[i].x),read(e[i].y),read(e[i].w); sort(e+1,e+m+1,cmp); for(i=1;i<=m;i++)val[n+i]=sum[n+i]=e[i].w,from[n+i]=n+i; for(i=1;i<=m;i++){ root[i]=root[i-1]; if(F(e[i].x)==F(e[i].y)){ j=askfrom(e[i].x,e[i].y); cut(j,e[j-n].x),cut(j,e[j-n].y); root[i]=ins(root[i],1,m,j-n,-e[j-n].w); }else fa[fa[e[i].x]]=fa[e[i].y]; link(e[i].x,n+i),link(e[i].y,n+i); root[i]=ins(root[i],1,m,i,e[i].w); } read(q); while(q--){ read(x),read(y),x-=ans,y-=ans; printf("%d\n",ans=ask(root[getid(x)],1,m,lower(y),m)); } for(i=tot=ans=0;i<=n+m;i++)f[i]=son[i][0]=son[i][1]=val[i]=sum[i]=from[i]=rev[i]=0; for(i=1;i<=n;i++)fa[i]=0; for(i=1;i<=m;i++)root[i]=0; } return 0; }