• bzoj 2238 Mst


    显然先求出最小生成树

    如果删的是非树边就不用管,还是能取最小生成树

    如果删的是树边就有非树边可以替代它

    反向考虑,每条非树边可以替代最小生成树上一条路径的边

    所以树剖加线段树,对每条非树边在树上更新对应的那一段的答案就行了

    代码异常丑陋~~~

    #include<bits/stdc++.h>
    #define il inline
    #define vd void
    typedef long long ll;
    il int gi(){
    	int x=0,f=1;
    	char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')f=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    struct edge{int x,y,i,w;}s[100010];
    il bool cmp1(const edge&a,const edge&b){return a.w<b.w;}
    il bool cmp2(const edge&a,const edge&b){return a.i<b.i;}
    int Fa[50010];
    il int hd(int x){return Fa[x]==x?x:Fa[x]=hd(Fa[x]);}
    il vd Union(int a,int b){Fa[hd(a)]=hd(b);}
    int dfn[50010],son[50010],siz[50010],fa[50010],top[50010],dep[50010];
    int fir[50010],nxt[100010],dis[100010],id,num[100010];
    il vd link(int a,int b,int c){
    	nxt[++id]=fir[a],fir[a]=id,dis[id]=b,num[id]=c;
    	nxt[++id]=fir[b],fir[b]=id,dis[id]=a,num[id]=c;
    }
    int NUM[100010];
    il vd dfs(int x){
    	siz[x]=1;
    	for(int i=fir[x];i;i=nxt[i]){
    		if(fa[x]==dis[i])continue;
    		fa[dis[i]]=x;dep[dis[i]]=dep[x]+1;
    		NUM[num[i]]=dis[i];
    		dfs(dis[i]);
    		siz[x]+=siz[dis[i]];
    		if(siz[son[x]]<siz[dis[i]])son[x]=dis[i];
    	}
    }
    il vd dfs2(int x,int tp){
    	top[x]=tp;dfn[x]=++dfn[0];
    	if(son[x])dfs2(son[x],tp);
    	for(int i=fir[x];i;i=nxt[i])
    		if(dis[i]!=fa[x]&&dis[i]!=son[x])
    			dfs2(dis[i],dis[i]);
    }
    int lz[200010],ans[100010];
    #define mid ((l+r)>>1)
    il vd update(int x,int l,int r,const int&L,const int&R,const int&d){
    	if(L<=l&&r<=R){lz[x]=std::min(lz[x],d);return;}
    	if(L<=mid)update(x<<1,l,mid,L,R,d);
    	if(mid<R)update(x<<1|1,mid+1,r,L,R,d);
    }
    il vd down(int x,int l,int r){
    	if(l==r){ans[l]=lz[x];return;}
    	lz[x<<1]=std::min(lz[x<<1],lz[x]);
    	lz[x<<1|1]=std::min(lz[x<<1|1],lz[x]);
    	down(x<<1,l,mid),down(x<<1|1,mid+1,r);
    }
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("2238.in","r",stdin);
    	freopen("2238.out","w",stdout);
    #endif
    	int n=gi(),m=gi();
    	for(int i=1;i<=m;++i)s[i].x=gi(),s[i].y=gi(),s[i].w=gi(),s[i].i=i;
    	std::sort(s+1,s+m+1,cmp1);
    	int q=gi();
    	for(int i=1;i<=n;++i)Fa[i]=i;
    	int t=1;ll ANS=0;
    	for(int i=1;i<n;++i){
    		while(t<=m&&hd(s[t].x)==hd(s[t].y))++t;
    		if(t>m){
    			while(q--)puts("Not connected");
    			return 0;
    		}
    		Union(s[t].x,s[t].y);
    		link(s[t].x,s[t].y,s[t].i);
    		ANS+=s[t].w;
    	}
    	std::sort(s+1,s+m+1,cmp2);
    	dfs(1),dfs2(1,1);
    	for(int i=1;i<=n*4;++i)lz[i]=1e9;
    	for(int i=1;i<=m;++i)
    		if(!NUM[i]){
    			int x=s[i].x,y=s[i].y;
    			while(top[x]!=top[y]){
    				if(dep[top[x]]>dep[top[y]])update(1,1,n,dfn[top[x]],dfn[x],s[i].w),x=fa[top[x]];
    				else update(1,1,n,dfn[top[y]],dfn[y],s[i].w),y=fa[top[y]];
    			}
    			if(dep[x]>dep[y])std::swap(x,y);
    			update(1,1,n,dfn[x]+1,dfn[y],s[i].w);
    		}
    	down(1,1,n);
    	while(q--){
    		int x=gi();
    		if(NUM[x]){
    			if(ans[dfn[NUM[x]]]==1e9)puts("Not connected");
    			else printf("%lld
    ",ANS-s[x].w+ans[dfn[NUM[x]]]);
    		}else printf("%lld
    ",ANS);
    	}
    	return 0;
    }
    
  • 相关阅读:
    【LeetCode】Set Matrix Zeroes 解题报告
    CodeForces 14 E
    Linux守护进程的编程实现
    用fildder 查看loveuv 刷流量时通信的数据
    .NET MVC学习笔记(一)
    微价值:专訪《甜心爱消除》个人开发人员Lee,日入千元!
    JSP动作--JSP有三种凝视方式
    【Hibernate步步为营】--映射合集汇总
    阿里好的开源项目有哪些(善用工具)
    色彩搭配原理与技巧?
  • 原文地址:https://www.cnblogs.com/xzz_233/p/9722008.html
Copyright © 2020-2023  润新知