[最小生成树][树链剖分]mst

BZOJ2238
题意:给一张图,多次询问删去其中一条边后mst大小,删去后图不连通输出Not connected,询问之间相互独立

分析:
一个显然的结论是一条非MST上的边会和MST形成一个环,这个环上任意断开一条边都可以形成一棵生成树
所以我们只需要对于所有非树边,把它能够更新的所有边都打上标记
询问一条边上的所有标记中的最小值即可
注意如果原图不连通,直接全部输出Not connected

Code:

#include<bits/stdc++.h>
#define INF 1e9
#define ls tr[k].l
#define rs tr[k].r
#define mid ((ls+rs)>>1)
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=100005;
struct E{int x,y,z;int num;}e[N<<1];
int n,m,q,u,v,w;
int vis[N<<1],head[N<<1],nxt[N<<1],c[N<<1],tot=0;
int fa[N],pt[N],dep[N],siz[N],hson[N];
int top[N],dfn[N],id[N],sign=0;
int ff[N],a[N];
int ise[N];
int mst=0;
namespace segtree{
	struct segtree{int l,r,mx,tag;}tr[N<<2];
	inline void pushup(int k) {tr[k].mx=min(tr[k<<1].mx,tr[k<<1|1].mx);}
	inline void pushmx(int k,int v){tr[k].mx=min(tr[k].mx,v);tr[k].tag=min(tr[k].tag,v);}
	inline void pushdown(int k){
		if(tr[k].tag){
			pushmx(k<<1,tr[k].tag);
			pushmx(k<<1|1,tr[k].tag);
			tr[k].tag=INF;
		}
	}
	void build(int k,int l,int r){
		ls=l,rs=r,tr[k].tag=INF;
		if(l==r) {tr[k].mx=INF;return;}
		build(k<<1,l,mid);build(k<<1|1,mid+1,r);
		pushup(k);
	}
	void modify(int k,int ql,int qr,int v){
		if(ql>rs || qr<ls) return;
		if(ql<=ls && rs<=qr) {pushmx(k,v);return;}
		pushdown(k);
		if(qr<=mid) modify(k<<1,ql,qr,v);
		else if(ql>mid) modify(k<<1|1,ql,qr,v);
		else modify(k<<1,ql,mid,v),modify(k<<1|1,mid+1,qr,v);
		pushup(k);
	}
	int query(int k,int ql,int qr){
		if(ql>rs || qr<ls) return INF;
		if(ql<=ls && rs<=qr) return tr[k].mx;
		pushdown(k);
		if(qr<=mid) return query(k<<1,ql,qr);
		else if(ql>mid) return query(k<<1|1,ql,qr);
		else return min(query(k<<1,ql,mid),query(k<<1|1,mid+1,qr));
		pushup(k);
	}
}
namespace tree{
	using namespace segtree;
	int get(int v){return v==ff[v]?v:ff[v]=get(ff[v]);}
	inline void add(int x,int y,int z) {vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
	inline bool cmp(E a,E b) {return a.z<b.z;}
	inline bool cmp1(E a,E b) {return a.num<b.num;}
	inline int kruscal(){
		int tott=0;
		for(int i=1;i<=n;i++) ff[i]=i;
		sort(e+1,e+m+1,cmp);
		for(int i=1;i<=m;i++){
			int xx=get(e[i].x),yy=get(e[i].y);
			if(xx==yy) continue;ise[e[i].num]=1;
			++tott;ff[xx]=yy;add(e[i].x,e[i].y,e[i].z);add(e[i].y,e[i].x,e[i].z);
			mst+=e[i].z;
		}
		return tott;
	}
	void dfs1(int v){
		pt[v]=siz[v]=1;int maxn=0;
		for(int i=head[v];i;i=nxt[i]){
			int y=vis[i];
			if(pt[y]) continue;
			dep[y]=dep[v]+1; fa[y]=v; a[y]=c[i];
			dfs1(y);
			siz[v]+=siz[y];
			if(siz[y]>maxn) maxn=siz[y],hson[v]=y;
		}
	}
	void dfs2(int v){
		dfn[v]=++sign;id[sign]=v;
		if(hson[v]) top[hson[v]]=top[v],dfs2(hson[v]);
		for(int i=head[v];i;i=nxt[i]) if(!top[vis[i]]) top[vis[i]]=vis[i],dfs2(vis[i]);
	}
	inline void change(int x,int y,int z){ 
		while(top[x]!=top[y]){
			if(dep[top[x]]<dep[top[y]]) swap(x,y);
			 modify(1,dfn[top[x]],dfn[x],z);x=fa[top[x]];
		}
		if(dep[x]<dep[y]) swap(x,y);
		modify(1,dfn[y]+1,dfn[x],z);
	}
	inline int ask(int x,int y){
		int ret=INF;
		while(top[x]!=top[y]){
			if(dep[top[x]]<dep[top[y]]) swap(x,y);
			 ret=min(ret,query(1,dfn[top[x]],dfn[x]));x=fa[top[x]];
		}
		if(dep[x]<dep[y]) swap(x,y);
		ret=min(ret,query(1,dfn[y]+1,dfn[x]));
		return ret;
	}
	inline void work(){
		int flag=1;
		n=read(),m=read();
		for(int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].z=read(),e[i].num=i;
		if(kruscal()<n-1) flag=0;
		dfs1(1);top[1]=1;dfs2(1);build(1,1,n);
		sort(e+1,e+m+1,cmp1);
		for(int i=1;i<=m;i++) if(!ise[i]) change(e[i].x,e[i].y,e[i].z);
		q=read();
		if(!flag){
			while(q--) puts("Not connected");
		}
		else while(q--){
			u=read();
			if(!ise[u]) cout<<mst<<'\n';
			else{
				int ans=mst-e[u].z;
				int aaa=ask(e[u].x,e[u].y);
				if(aaa==INF) {puts("Not connected");continue;}
				ans+=aaa;
				cout<<ans<<'\n';
			}
		}
	}
}
int main(){
	tree::work();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43346903/article/details/86569627