正题
题目链接:https://www.luogu.org/problem/P4764
题目大意
给出一张图,若干个询问,每个询问求只使用权值在[L,R][L,R][L,R]这个范围内的边组成的最小生成树权值和,强制在线。
解题思路
我们先考虑LLL固定,这时我们发现我们可以从LLL开始往右做最小生成树,若一条边可以产生贡献值就为该边权值,否则权值为0,然后我们在线段树上修改查询即可。
但是现在LLL端点固定,我们考虑从大到小加边,我们加入一条更小的边(x,y,w)(x,y,w)(x,y,w),若x,yx,yx,y不联通就直接加入,若联通就选取x,yx,yx,y路径上权值最大的一条边删去即可,这个我们用LCTLCTLCT可以O(logn)O(\log n)O(logn)维护。
然后因为强制在线所以我们可以用主席树储存答案。
LCTLCTLCT维护最小生成树,我们可以将一条边拆成两个点和一条边,然后路径查询即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int N=200010,M=3600010;
int T,n,m,q,ans,from[N],sum[N],val[N],fa[N],root[N];
struct Line_Cut_Tree{#define ls son[x][0]#define rs son[x][1]int son[N][2],fa[N];bool r[N];stack<int> s;bool Nroot(int x){return fa[x]&&(son[fa[x]][0]==x||son[fa[x]][1]==x);}void PushUp(int x){sum[x]=val[x];from[x]=x;if(son[x][0]&&sum[ls]>sum[x]) sum[x]=sum[ls],from[x]=from[ls];if(son[x][1]&&sum[rs]>sum[x]) sum[x]=sum[rs],from[x]=from[rs];return;}void PushR(int x){swap(ls,rs);r[x]^=1;return;}void PushDown(int x){if(r[x])PushR(ls),PushR(rs),r[x]^=1;return;}void Rotate(int x){int y=fa[x],z=fa[y],k=(son[y][1]==x),w=son[x][!k];if(Nroot(y)) son[z][son[z][1]==y]=x;son[x][!k]=y;son[y][k]=w;if(w) fa[w]=y;fa[y]=x;fa[x]=z;PushUp(y);return;}void Splay(int x){int y=x,z=0;s.push(x);while(Nroot(s.top())) s.push(fa[s.top()]);while(!s.empty()) PushDown(s.top()),s.pop();while(Nroot(x)){y=fa[x];z=fa[y];if(Nroot(y))Rotate((son[y][0]==x)^(son[z][0]==y)?x:y);Rotate(x);}PushUp(x);return;}void Access(int x){for(int y=0;x;x=fa[y=x])Splay(x),rs=y,PushUp(x);return;}void MakeRoot(int x){Access(x);Splay(x);PushR(x);return;}int Split(int x,int y){MakeRoot(x);Access(y);Splay(y);return from[y];}void Link(int x,int y){MakeRoot(x);fa[x]=y;Access(x);return;}void Cut(int x,int y){MakeRoot(x);Access(y);Splay(y);fa[son[y][0]]=0;son[y][0]=0;PushUp(y);return;}void Clean(){memset(son,0,sizeof(son));memset(fa,0,sizeof(fa));memset(r,0,sizeof(r));}#undef ls#undef rs
}LCT;
struct Keep_Seq_Tree{int w[M],lson[M],rson[M],cnt;int Insert(int y,int L,int R,int pos,int val){int x=++cnt;w[x]=w[y]+val;lson[x]=lson[y];rson[x]=rson[y];if(L==R) return x;int mid=(L+R)>>1;if(pos<=mid) lson[x]=Insert(lson[y],L,mid,pos,val);else rson[x]=Insert(rson[y],mid+1,R,pos,val);return x;}int Query(int x,int L,int R,int l,int r){if(!x) return 0;if(L>R) return 0;if(L==l&&R==r) return w[x];int mid=(L+R)>>1;if(r<=mid) return Query(lson[x],L,mid,l,r);if(l>mid) return Query(rson[x],mid+1,R,l,r);return Query(lson[x],L,mid,l,mid)+Query(rson[x],mid+1,R,mid+1,r);}
}Tree;
struct Enode{int x,y,w;
}a[N];
int Find(int x)
{return fa[x]==x?x:fa[x]=Find(fa[x]);}
bool cmp(Enode x,Enode y)
{return x.w>y.w;}
int get_idx(int x)
{int l=1,r=m;while(l<=r){int mid=(l+r)>>1;if(a[mid].w>=x) l=mid+1;else r=mid-1;}return min(r,m);
}
int get_idy(int x)
{int l=1,r=m;while(l<=r){int mid=(l+r)>>1;if(a[mid].w>x) l=mid+1;else r=mid-1;}return min(l,m);
}
int main()
{scanf("%d",&T);while(T--){LCT.Clean();Tree.cnt=0;ans=0;memset(val,0,sizeof(val));memset(sum,0,sizeof(sum));memset(from,0,sizeof(from));scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) fa[i]=i;for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);sort(a+1,a+1+m,cmp);for(int i=1;i<=m;i++)val[i+n]=sum[i+n]=a[i].w,from[i+n]=i+n;for(int i=1;i<=m;i++){root[i]=root[i-1];if(Find(a[i].x)==Find(a[i].y)){int p=LCT.Split(a[i].x,a[i].y);LCT.Cut(p,a[p-n].x);LCT.Cut(p,a[p-n].y);root[i]=Tree.Insert(root[i],1,m,p-n,-a[p-n].w);}else fa[fa[a[i].x]]=fa[a[i].y];LCT.Link(a[i].x,i+n);LCT.Link(a[i].y,i+n);root[i]=Tree.Insert(root[i],1,m,i,a[i].w);}scanf("%d",&q);while(q--){int x,y,idx,idy;scanf("%d%d",&x,&y);x-=ans;y-=ans;idx=get_idx(x);idy=get_idy(y);ans=Tree.Query(root[idx],1,m,idy,m);printf("%d\n",ans);}}
}