zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",sum-edge[t].wei+tmp);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    mysql这个垃圾迁移数据费劲半天
    https请求,可设置请求格式
    mybatis plus 使用
    https请求,get post 通用
    根据经纬度,查询最近距离
    redis与mysql一致性
    导入excel
    在idea中git怎么使用
    spring的传播机制
    通过RequestContextHolder获取HttpServletRequest
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13393129.html
Copyright © 2011-2022 走看看