BZOJ2238Mst题解

预处理出完整图的最小生成树之后。

首先分类讨论。

如果我们删的是一条非树边的话,对最小生成树没有影响,直接输出即可。

但如果删的是一条树边的话,就需要拉一条非树边连起断开的联通块。

我们画图观察一手

蓝色的非树边可以替代粉色边的作用

也就是说,非树边能把其端点左右之间的路径都替换了

那我们树剖下来,用线段树维护每条树边能被非树边代替的最小权值

比如

我们最开始连了蓝色这条非树边,他的权值是114514。

那么粉色边在线段树上的最小值将都被更新为114514

再连一条黄边

受影响的路径为蓝色

就这样你删那条边,你就在原生成树的基础上减去此边权值再加上他在线段树上能被非树边代替的最小权值即可

Code

cpp 复制代码
#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#define ll long long
#define db(x) do{ cerr<<x<<' '; }while(0)
#define linux
using namespace std;
#ifdef linux
	#define getchar getchar_unlocked
#endif
inline ll read(){
	ll x=0;int f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}
const int N=100002;
const int M=100002;
const int inf=1e9;
int n,m,head[N],nxt[N<<1],to[N<<1],eidx,fa[N],siz[N],dep[N],son[N],dfn[N],wr[N],topf[N],dfnidx,a[N],ww[N<<1],q;
ll ans;
int mp[N];
struct edge{ int x,y; ll w; int id; bool vis; }e[M];
void add(int x,int y,ll w){ to[++eidx]=y; nxt[eidx]=head[x]; ww[eidx]=w; head[x]=eidx; }
int getfa(int x){ return fa[x]==x?x:fa[x]=getfa(fa[x]); }
bool mycmp(edge x,edge y){ return x.w<y.w; }
bool cmp(edge x,edge y){ return x.id<y.id; }
void Kruscal(){
	int num=0;
	sort(e+1,e+m+1,mycmp);
	for(int i=1;i<=m;i++){
		mp[e[i].id]=i;
		int x=e[i].x,y=e[i].y;
		ll w=e[i].w;
		x=getfa(x),y=getfa(y);
		if(x==y) continue;
		num++;
		ans+=w;
		e[i].vis=1;
		fa[x]=y;
		add(e[i].x,e[i].y,w);
		add(e[i].y,e[i].x,w);
		if(num==n-1) return ;
	}
	ans=inf;
}
void dfs1(int x,int f){
	siz[x]=1; dep[x]=dep[f]+1; fa[x]=f;
	int maxx=-1;
	for(int i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==f) continue;
		a[y]=ww[i];
		dfs1(y,x);
		siz[x]+=siz[y];
		if(siz[y]>maxx) maxx=siz[y],son[x]=y;
	}
}
void dfs2(int x,int tpf){
	dfn[x]=++dfnidx; wr[dfnidx]=a[x]; topf[x]=tpf;
	if(!son[x]) return ;
	dfs2(son[x],tpf);
	for(int i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa[x]||y==son[x]) continue;
		dfs2(y,y);
	}
}
#define lc p<<1
#define rc p<<1|1
struct node{
	ll minn,tag;
	#define minn(x) t[x].minn
	#define tag(x) t[x].tag
}t[N<<2];
void pushup(int p){
	minn(p)=min(minn(lc),minn(rc));
}
void pushdown(int p,int l,int r){
	if(tag(p)==inf) return ;
	ll val=tag(p);
	minn(lc)=min(minn(lc),val); tag(lc)=min(tag(lc),val);
	minn(rc)=min(minn(rc),val); tag(rc)=min(tag(rc),val);
	tag(p)=inf;
}
void build(int p,int l,int r){
	minn(p)=inf; tag(p)=inf;
	if(l==r) return ;
	int mid=(l+r)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	pushup(p);
}
void update(int p,int l,int r,int ql,int qr,ll val){
	if(ql<=l&&r<=qr){ minn(p)=min(minn(p),val); tag(p)=min(tag(p),val); return ; }
	pushdown(p,l,r);
	int mid=(l+r)>>1;
	if(ql<=mid) update(lc,l,mid,ql,qr,val);
	if(qr>mid)  update(rc,mid+1,r,ql,qr,val);
	pushup(p);
}
ll ask(int p,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr) return minn(p);
	int mid=(l+r)>>1;
	pushdown(p,l,r);
	ll res=inf;
	if(ql<=mid) res=min(res,ask(lc,l,mid,ql,qr));
	if(qr>mid)  res=min(res,ask(rc,mid+1,r,ql,qr));
	return res;
}
void updatechain(int x,int y,ll val){
	while(topf[x]!=topf[y]){
		if(dep[topf[x]]<dep[topf[y]]) swap(x,y);
		update(1,1,n,dfn[topf[x]],dfn[x],val);
		x=fa[topf[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	if(x!=y) update(1,1,n,dfn[x]+1,dfn[y],val);
}
ll askchain(int x,int y){
	ll res=inf;
	while(topf[x]!=topf[y]){
		if(dep[topf[x]]<dep[topf[y]]) swap(x,y);
		res=min(res,ask(1,1,n,dfn[topf[x]],dfn[x]));
		x=fa[topf[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	if(x!=y) res=min(res,ask(1,1,n,dfn[x]+1,dfn[y]));
	return res;
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].w=read(),e[i].id=i;
	for(int i=1;i<=n;i++) fa[i]=i;
	Kruscal();
	for(int i=1;i<=n;i++) fa[i]=0;
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	for(int i=1;i<=m;i++) if(!e[i].vis) updatechain(e[i].x,e[i].y,e[i].w);
	q=read();
	if(ans==inf){
		while(q--) cout<<"Not connected"<<'\n';
		return 0;
	}
	while(q--){
		int id=mp[read()];
		if(!e[id].vis) cout<<ans<<'\n';
		else{
			ll tmp=askchain(e[id].x,e[id].y);
			if(tmp==inf) cout<<"Not connected"<<'\n';
			else cout<<ans+tmp-e[id].w<<'\n';
		}
	}	
	return 0;
}