[BZOJ] 4326: NOIP2015 运输计划

二分答案,把原问题转化为\(log\)个判定问题

现在问题是,给出一个答案\(t\),问是否可行

我们找出\(len>t\)的所有路径,这些路径都要被变短,也就要找到这些路径的一条最长公共边

如何找最长公共边?先考虑公共边,可以用树上差分解决,最长就顺便取max即可

//Stay foolish,stay hungry,stay young,stay simple
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
using namespace std;

inline int rd(){
	int ret=0;char c;
	while(c=getchar(),!isdigit(c));
	while(isdigit(c))ret=ret*10+c-'0',c=getchar();
	return ret;
}

const int MAXN =300005,M=300005;
int n,m;
struct Edge{
	int nex,to,w;
}e[M<<1];
int ecnt,head[MAXN];
inline void add(const int x,const int y,const int w){
	e[++ecnt].nex = head[x];
	e[ecnt].to = y;
	e[ecnt].w = w;
	head[x] = ecnt;
}
int fa[MAXN],hs[MAXN],dep[MAXN];
int dfs1(int x,int pre,int w){
	fa[x]=pre;dep[x]=dep[pre]+w;
	int mx=0,tmp,siz=1;
	for(register int i=head[x];i;i=e[i].nex){
		int v=e[i].to;
		if(v==pre) continue;
		tmp=dfs1(v,x,e[i].w);siz+=tmp;
		if(tmp>mx){mx=tmp;hs[x]=v;}
	}
	return siz;
}
int top[MAXN];
void dfs2(int x,int tp){
	top[x]=tp;
	if(hs[x]) dfs2(hs[x],tp);
	for(register int i=head[x];i;i=e[i].nex){
		int v=e[i].to;
		if(v==fa[x]||v==hs[x]) continue;
		dfs2(v,v);	
	}
}
int lca(int x,int y){
	while(top[x]!=top[y])
		dep[top[x]]<dep[top[y]]?y=fa[top[y]]:x=fa[top[x]];
	return dep[x]<dep[y]?x:y;
}

struct Links{
	int x,y,l,len;
}lk[MAXN];
int num,mx,val[MAXN];
int d[MAXN];

void gfs(int x){
	for(register int i=head[x];i;i=e[i].nex){
		int v=e[i].to;
		if(v==fa[x]) continue;
		gfs(v);
		d[x]+=d[v];
	}
	if(d[x]==num){
		mx=max(mx,dep[x]-dep[fa[x]]);	
	}
}
bool check(int t){
	num=0;mx=0;
	memset(d,0,sizeof(d));
	int mxl=0;
	for(register int i=1;i<=m;i++){
		if(lk[i].len>t){
			num++;	
			d[lk[i].x]++;
			d[lk[i].y]++;
			d[lk[i].l]-=2;
			mxl=max(mxl,lk[i].len);
		}
		
	}
	gfs(1);
	return (mxl-mx<=t);
}

signed main(){
	n=rd();m=rd();
	int x,y,w;
	for(register int i=1;i<=n-1;i++){
		x=rd();y=rd();w=rd();
		add(x,y,w);add(y,x,w);
	}
	dfs1(1,0,0);dfs2(1,1);
	for(register int i=1;i<=m;i++){
		x=lk[i].x=rd();
		y=lk[i].y=rd();
		int l=lca(x,y);
		lk[i].l=l;
		lk[i].len=dep[x]+dep[y]-(dep[l]<<1);
	}
	int l=0,r=3e8,mid,ans;
	while(l<=r){
		mid=(l+r)>>1;
		if(check(mid))ans=mid,r=mid-1;
		else l=mid+1;
	}
	cout<<ans;
	return 0;
}
posted @ 2018-10-13 08:45  GhostCai  阅读(90)  评论(0编辑  收藏  举报