zoukankan      html  css  js  c++  java
  • [20200801NOIP提高组模拟T2]电话线铺设

    Description

    给定(n)点,(w)条带权白边,(l)条带权黑边.现需用(n-2)条白边和(1)条黑边构造出(MST).请输出(MST)大小及所用的白边编号和黑边编号.(注:有可能光用白边构造不出(MST))

    solution

    做这题的时候挺坎坷的.先是打了45pts暴力,然后想出正解但没时间也不想打了.

    其实思路很简单.对于光用白边构造不出(MST)的点,我们直接白边尽量构造(MST),然后黑边补充即可.对于其它数据点,我们可以先用白边构造(MST),然后再一一枚举每条黑边.设黑边端点为(x,y),则我们可以断掉(MST)(<x,y>)之间路径上权值最大的边,然后将边(x,y)连上即可.试问如何找最大权值边?树上倍增即可.

    code

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<map>
    #define R register
    #define next kdjadskfj
    #define debug puts("mlg")
    #define mod 1000000007
    #define Mod(x) ((x%mod+mod)%mod)
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    inline ll read();
    inline void write(ll x);
    inline void writeln(ll x);
    inline void writesp(ll x);
    struct node{
    	ll x,y,z,name1;
    	bool operator <(node const &X)const{return z<X.z;}
    }W[220000],B[220000];
    ll n,w,l;
    ll f[220000];
    ll sum,ans,Ans;
    bool vis[220000];
    ll head[550000],next[550000],to[550000],tot,c[550000];
    ll d[210000],F[210000][20],M[210000][20];
    ll AnsL,AnsR,Maxn,tag,pre[210000],last[210000];
    
    inline ll getf(ll x){return f[x]==x?x:f[x]=getf(f[x]);}
    
    inline void merge(ll x,ll y){f[getf(x)]=getf(y);}
    
    inline bool check(ll x,ll y){return getf(x)==getf(y);}
    
    inline void solve1(){
    	Maxn=((ull)1<<63)-1;
    	for(R ll i=1;i<=l;i++){
    			if(!check(B[i].x,B[i].y)){
    				if(Maxn>ans+B[i].z){
    					Maxn=ans+B[i].z;
    					Ans=B[i].name1;
    				}
    			}
    		}
    		ans=Maxn;
    		writeln(ans);
    		for(R ll i=1;i<=w;i++) if(vis[i]) writeln(i);
    		writeln(Ans);
    	exit(0);
    }
    
    inline void add(ll x,ll y,ll z){
    	to[++tot]=y;next[tot]=head[x];head[x]=tot;c[tot]=z;
    }
    
    inline void dfs1(ll x,ll fa,ll deep){
    	d[x]=deep;
    	F[x][0]=fa;
    	for(R ll i=head[x],ver;i;i=next[i]){
    		ver=to[i];
    		if(ver==fa) continue;
    		M[ver][0]=c[i];
    		dfs1(ver,x,deep+1);
    	}
    }
    
    inline void bz(){
    	for(R ll k=1;k<=19;k++)
    		for(R ll i=1;i<=n;i++)
    			F[i][k]=F[F[i][k-1]][k-1],M[i][k]=max(M[i][k-1],M[F[i][k-1]][k-1]);
    }
    
    inline ll lca(ll x,ll y){
    	ll maxn=0;
    	if(d[x]<d[y]) swap(x,y);
    	for(R ll i=19;i>=0;i--){
    		if(d[F[x][i]]>=d[y]){
    			maxn=max(M[x][i],maxn);
    			x=F[x][i];
    		}
    	}
    	if(x==y) return maxn;
    	for(R ll i=19;i>=0;i--){
    		if(F[x][i]!=F[y][i]){
    			maxn=max(maxn,max(M[x][i],M[y][i]));
    			x=F[x][i];y=F[y][i];
    		}
    	}
    	maxn=max(maxn,max(M[x][0],M[y][0]));		//这里还未跳到lca,所以还得再加最后一层判断.(一开始没加调了好久bug) 
    	return maxn;
    }
    
    inline void dfs2(ll x,ll fa){
    	for(R ll i=head[x],ver;i;i=next[i]){
    		ver=to[i];
    		if(ver==fa) continue;
    		dfs2(ver,x);
    		pre[ver]=x;last[ver]=i;
    	}
    }
    
    inline void solve2(){
    	dfs1(1,0,1);bz();
    	Maxn=(((ull)1<<63)-1);
    	for(R ll i=1;i<=l;i++){
    		ll len=lca(B[i].x,B[i].y);
    		if(ans-len+B[i].z<Maxn){
    			Maxn=ans-len+B[i].z;
    			AnsL=B[i].x;AnsR=B[i].y;
    			Ans=B[i].name1;
    			tag=len;
    		}
    	}
    	dfs2(AnsL,0);
    	for(R ll x=AnsR;x;x=pre[x]){
    		if(c[last[x]]==tag){
    			for(R ll i=1;i<=w;i++)
    				if(min(W[i].x,W[i].y)==min(x,pre[x])&&max(W[i].x,W[i].y)==max(x,pre[x])&&W[i].z==tag){vis[W[i].name1]=false;break;}			
    			break;
    		}
    	}
    	writeln(Maxn);
    	for(R ll i=1;i<=w;i++) if(vis[i]) writeln(i);
    	writeln(Ans);
    	exit(0);
    }
    int main(){
    	freopen("telephone.in","r",stdin);
    	freopen("telephone.out","w",stdout);
    	n=read();w=read();l=read();
    	for(R ll i=1;i<=w;i++){W[i].x=read();W[i].y=read();W[i].z=read();W[i].name1=i;}
    	sort(W+1,W+w+1);
    	for(R ll i=1;i<=l;i++){B[i].x=read();B[i].y=read();B[i].z=read();B[i].name1=i;}
    	for(R ll i=1;i<=n;i++)f[i]=i;
    	for(R ll i=1;i<=w;i++){
    		if(!check(W[i].x,W[i].y)){
    			++sum;
    			merge(W[i].x,W[i].y);
    			ans+=W[i].z;
    			vis[W[i].name1]=true;
    			add(W[i].x,W[i].y,W[i].z);
    			add(W[i].y,W[i].x,W[i].z);
    		}
    		if(sum==n-1) break;
    	}
    	if(sum!=n-1) solve1();
    	else solve2();
    }
    
    
  • 相关阅读:
    python基础(五)——CGI编程
    python基础(六)——mysql的使用
    python基础(七)——网络编程
    python基础(八)——多线程
    python面试题
    linux日志管理
    linux之nagios安装教程
    【华为云技术分享】盘点物联网常用开发板
    数据库“意外失联”?华为云DRS异地多活灾备为您支招
    如何处理暗数据?
  • 原文地址:https://www.cnblogs.com/ylwtsq/p/13416011.html
Copyright © 2011-2022 走看看