suxxsfe

一言(ヒトコト)

bzoj2238 Mst

https://darkbzoj.tk/problem/2238
树链剖分+线段树

给定一个无向带权图,多次询问,每次指定删除一条边,问删除之后图最小生成树的权值和,询问互相独立

其实还是比较简单的
考虑先把给定图的最小生成树跑出来
如果删除的边不在最小生成树上,那显然没有影响,直接输出权值和

如果在最小生成树上,则这个树被分成了两个部分,应该再加入一条边(显然要保留原有的没被删掉的边,如果更换它们,则会造成权值和增大,当然也有可能不变)
再加入的这一条边,应该两个端点一个分别在这个树被分成的这两部分上。取符合这样要求的边的最小权值
考虑哪些边符合这个要求不太容易,但可以考虑一个边能对哪些边产生作用(也就是哪些边删了,这个边可能会被选入)
想象一下就可以知道,是它两个端点在最小生成树上的简单路径经过的所有边
那么用树剖+线段树维护就行了,每次把路径上的边的值和这个边的值取一个 \(\min\)
所以真的挺简单的

注意是把边的信息下方到了点,所以这两个端点的 lca 的值不能被更改

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
int n,m;
#define N 100005
#define M 200005
struct graph{
	int fir[N],nex[M],to[M],wei[M],tot;
	inline void add(int u,int v,int w){
		to[++tot]=v;wei[tot]=w;
		nex[tot]=fir[u];fir[u]=tot;
	}
}G;
struct Edge{
	int x,y,wei,id;
}edge[100005];
int which[100005],on_tree[100005];
inline int cmp(Edge a,Edge b){return a.wei<b.wei;}
struct tr{
	tr *ls,*rs;
	int tag,min;
}dizhi[N*2],*root=&dizhi[0];
int tot;
int size[N],deep[N],fa[N],son[N];
int dfn[N],dfscnt,top[N];
int fa_[N];
int find(int k){return k==fa_[k]?k:fa_[k]=find(fa_[k]);}
void dfs1(int u){
	size[u]=1;deep[u]=deep[fa[u]]+1;
	for(reg int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(v==fa[u]) continue;
		fa[v]=u;dfs1(v);
		size[u]+=size[v];
		if(size[v]>size[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int topnow){
	top[u]=topnow;dfn[u]=++dfscnt;
	if(!son[u]) return;
	dfs2(son[u],topnow);
	for(reg int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(top[v]) continue;
		dfs2(v,v);
	}
}
inline void pushdown(tr *tree){
	if(tree->tag==1e9) return;
	int k=tree->tag;tree->tag=1e9;
	tree->ls->tag=std::min(tree->ls->tag,k);tree->rs->tag=std::min(tree->rs->tag,k);
	tree->ls->min=std::min(tree->ls->tag,k);tree->rs->min=std::min(tree->rs->tag,k);
}
void build(tr *tree,int l,int r){
	if(l==r) return tree->min=tree->tag=1e9,void();
	int mid=(l+r)>>1;
	tree->ls=&dizhi[++tot];tree->rs=&dizhi[++tot];
	build(tree->ls,l,mid);build(tree->rs,mid+1,r);
	tree->min=tree->tag=1e9;
}
int get(tr *tree,int l,int r,int pos){
	if(l==r) return tree->min;
	int mid=(l+r)>>1;
	pushdown(tree);
	return pos<=mid?get(tree->ls,l,mid,pos):get(tree->rs,mid+1,r,pos);
}
void change(tr *tree,int l,int r,int ql,int qr,int k){
	if(ql<=l&&r<=qr){
		tree->tag=std::min(tree->tag,k);tree->min=std::min(tree->min,k);
		return;
	}
	int mid=(l+r)>>1;
	pushdown(tree);
	if(ql<=mid) change(tree->ls,l,mid,ql,qr,k);
	if(qr>mid) change(tree->rs,mid+1,r,ql,qr,k);
}
inline void Change(int x,int y,int k){
	while(top[x]!=top[y]){
		if(deep[top[x]]<deep[top[y]]) x^=y,y^=x,x^=y;
		change(root,1,n,dfn[top[x]],dfn[x],k);
		x=fa[top[x]];
	}
	if(dfn[x]<dfn[y]) x^=y,y^=x,x^=y;
	if(dfn[x]>dfn[y]) change(root,1,n,dfn[y]+1,dfn[x],k);
}
int main(){
	n=read();m=read();
	for(reg int i=1;i<=m;i++) edge[i].x=read(),edge[i].y=read(),edge[i].wei=read(),edge[i].id=i;
	std::sort(edge+1,edge+1+m,cmp);
	for(reg int i=1;i<=m;i++) which[edge[i].id]=i;
	for(reg int i=1;i<=n;i++) fa_[i]=i;
	int sum=0,cnt=1;
	for(reg int i=1,x,y;cnt<n&&i<=m;i++){
		x=find(edge[i].x);y=find(edge[i].y);
		if(x==y) continue;
		fa_[x]=y;cnt++;on_tree[i]=1;sum+=edge[i].wei;
		G.add(edge[i].x,edge[i].y,edge[i].wei);G.add(edge[i].y,edge[i].x,edge[i].wei);
	}
	if(cnt!=n){
		int q=read();while(q--) puts("Not connected");
		return 0;
	}
//		printf("sum : %d\n",sum);
	dfs1(1);dfs2(1,1);
	build(root,1,n);
	for(reg int i=1;i<=m;i++)if(!on_tree[i]) Change(edge[i].x,edge[i].y,edge[i].wei);
	int q=read(),t;while(q--){
		t=which[read()];
		if(!on_tree[t]) printf("%d\n",sum);
		else{
			int tmp;
			if(edge[t].x==fa[edge[t].y]) tmp=edge[t].y;
			else tmp=edge[t].x;
			tmp=get(root,1,n,dfn[tmp]);
			if(tmp==1e9) puts("Not connected");
			else printf("%d\n",sum-edge[t].wei+tmp);
		}
	}
	return 0;
}
posted @ 2020-07-28 19:02  suxxsfe  阅读(133)  评论(0编辑  收藏  举报