题意
动态改边权MSTMST
题解
考虑和线段树分治+LCT+LCT一样的思想,对修改时间分治
考虑一段时间的修改的那些边
暴力就是当L=RL=R时直接让修改生效,,然后求一遍
这样是不行的因为图的规模没有还是mm
所以在每一层分治中就是考虑怎么缩小图的规模
考虑一个修改的两种极端情况
把这条边变成−∞−∞
我们把这个分治区间[L,R][L,R]要修改的边边权全部赋值为−∞,−∞,然后求一遍MSTMST
那么可以发现,,当前还在中的非−∞−∞边在以后也一定会在MSTMST中
所以我们考虑缩点,把这些边连成的联通块缩成一个点,,然后把答案加上
这样是会形成一个森林的所以我们要把连接森林的边存下来继续分治
2.2.把这条边变成∞∞
我们把这个分治区间[L,R][L,R]要修改的边边权全部赋值为∞,∞,然后求一遍MSTMST
那么可以发现,,当前不在中的边在之后的分治过程中一定是不需要了的
所以我们只要保存那些MSTMST中的边和权值为∞∞的边,然后继续分治
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=5e4+5,inf=1e9;
typedef int arr[N];
typedef long long ll;
struct mdy{int x,y;}p[N];
struct eg{
int u,v,w,id;
inline bool operator<(const eg b)const{return w<b.w;}
}e[18][N],d[N],t[N];
int n,m,q,Sum[18];arr a,c,fa,sz;ll ans[N];
int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);}
inline void link(int u,int v){
u=gf(u),v=gf(v);if(sz[u]>sz[v])swap(u,v);
fa[u]=v;sz[v]+=sz[u];
}
inline void clr(int T,eg*a){
fp(i,1,T){
fa[a[i].u]=a[i].u;
fa[a[i].v]=a[i].v;
sz[a[i].u]=sz[a[i].v]=1;
}
}
inline void contraction(int&T,ll&val){
int tp=0;
clr(T,d);sort(d+1,d+T+1);
fp(i,1,T)if(gf(d[i].u)^gf(d[i].v))
link(d[i].u,d[i].v),t[++tp]=d[i];
clr(tp,t);
fp(i,1,tp)if(t[i].w!=-inf&&gf(t[i].u)^gf(t[i].v))
val+=t[i].w,link(t[i].u,t[i].v);
tp=0;
fp(i,1,T)if(gf(d[i].u)^gf(d[i].v))
t[++tp]={fa[d[i].u],fa[d[i].v],d[i].w,d[i].id};
fp(i,1,tp)c[d[i].id]=i,d[i]=t[i];T=tp;
}
inline void reduction(int&T){
int tp=0;
clr(T,d);sort(d+1,d+T+1);
fp(i,1,T)
if(gf(d[i].u)^gf(d[i].v))
link(d[i].u,d[i].v),t[++tp]=d[i];
else if(d[i].w==inf)t[++tp]=d[i];
fp(i,1,tp)c[d[i].id]=i,d[i]=t[i];T=tp;
}
void cdq(int L,int R,int dep,ll val){
int T=Sum[dep];
if(L==R)a[p[L].x]=p[L].y;
fp(i,1,T){
e[dep][i].w=a[e[dep][i].id];
d[i]=e[dep][i],c[d[i].id]=i;
}
if(L==R){
ans[L]=val;clr(T,d);
sort(d+1,d+T+1);
fp(i,1,T)if(gf(d[i].u)^gf(d[i].v))
link(d[i].u,d[i].v),ans[L]+=d[i].w;
return;
}
fp(i,L,R)d[c[p[i].x]].w=-inf;
contraction(T,val);
fp(i,L,R)d[c[p[i].x]].w=inf;
reduction(T);
fp(i,1,T)e[dep+1][i]=d[i];
Sum[dep+1]=T;int mid=(L+R)>>1;
cdq(L,mid,dep+1,val);
cdq(mid+1,R,dep+1,val);
}
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
sd(n),sd(m),sd(q);
fp(i,1,m){int u,v;
sd(u),sd(v),sd(a[i]);
e[0][i]={u,v,a[i],i};
}
fp(i,1,q)sd(p[i].x),sd(p[i].y);
Sum[0]=m;cdq(1,q,0,0);
fp(i,1,q)we(ans[i]);
return Ot(),0;
}
这题用线段树分治竟然没卡过看来窝常数还是太大了