IOI 2013 Deaming

Description:

n n n个点 m m m条边的图,现在加 n − 1 − m n-1-m n1m条长度为 L e n Len Len的边使之变为一棵树,求树的直径的最小值。
n ≤ 1 0 5 n\le10^5 n105

Solution:

  • 比较裸的题了…
  • 初始,我们预处理出每个树的直径,求出直径上最佳的中点 m i d mid mid( d = m i n { m a x { d i s [ m i d ] , d i s [ R ] − d i s [ m i d ] } } d=min\{max\{dis[mid],dis[R]-dis[mid]\}\} d=min{max{dis[mid],dis[R]dis[mid]}}),拿这些中点来连边。
  • 最优的连边策略,一定是拿拥有最长的 d d d的中点与其它中点建边。
  • 建完边后再求一遍直径即为答案。

Code:

#include
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i=i##_end_;--i)
#define ll long long
templateinline bool chkmin(T&x,T y){return x>y?x=y,1:0;}
templateinline bool chkmax(T&x,T y){return xinline void rd(T&x){
	x=0;char c;
	while((c=getchar())<48);
	do x=(x<<1)+(x<<3)+(c^48);
	while((c=getchar())>47);
}

const int N=1e5+2,INF=0x3f3f3f3f;

int n,m;
ll Len;

int qwq,head[N];
struct edge{
	int to,nxt;
	ll w;
}E[N<<1];
void addedge(int x,int y,ll z){E[qwq]=(edge){y,head[x],z};head[x]=qwq++;}
#define EREP(x) for(int i=head[x];~i;i=E[i].nxt)

struct p100{
	
	ll dis[N];
	int fa[N];
	ll Mn[N];// 每个小树的 min{max{dis[L][mid],dis[mid][R]}} 
	int rt[N],cnt;// 每个小树的中点 
	
	bool vis[N];
	
	int Id;
	ll Mx;
	
	void dfs1(int x,int f,ll d){
		if(chkmax(Mx,d)) Id=x;
		vis[x]=1;
		EREP(x){
			int y=E[i].to;
			if(y==f)continue;
			dfs1(y,x,d+E[i].w);
		}
	}
	
	void dfs2(int x,int f,ll d){
		if(chkmax(Mx,d)) Id=x;
		fa[x]=f;
		dis[x]=d;
		EREP(x){
			int y=E[i].to;
			if(y==f)continue;
			dfs2(y,x,d+E[i].w);
		}
	}
	
	void solve(){
		REP(i,1,n) if(!vis[i]) {
			Id=Mx=-1;
			dfs1(i,0,0);
			rt[++cnt]=Id;//L
			Mx=-1;
			dfs2(Id,0,0);//R
			int R=Id,L=rt[cnt],mid=R;
			Mn[cnt]=INF;
			if(L==R) Mn[cnt]=0;
			while(mid!=L){
				if(chkmin(Mn[cnt],max(dis[mid],dis[R]-dis[mid])))rt[cnt]=mid;
				mid=fa[mid];
			}
		}
		
		ll mx1=-1;
		int Rt1=-1;
		
		REP(i,1,cnt)if(chkmax(mx1,Mn[i])) Rt1=rt[i];
		
		REP(i,1,cnt){
			if(Rt1==rt[i])continue;
			addedge(Rt1,rt[i],Len);
			addedge(rt[i],Rt1,Len);
		}
		
		Mx=Id=-1;
		dfs1(1,0,0);
		Mx=-1;
		dfs2(Id,0,0);
		printf("%lld\n",Mx);
		
	}
}p2;

int main(){
//	freopen("dreaming.in","r",stdin);
//	freopen("dreaming.out","w",stdout);
	rd(n),rd(m),rd(Len);
	memset(head,-1,sizeof head);
	REP(i,1,m){
		int a,b,c;
		rd(a),rd(b),rd(c);
		++a,++b;
		addedge(a,b,c);
		addedge(b,a,c);
	}
	
	p2.solve();
	return 0;
}

你可能感兴趣的:(算法,IOI)