【题解】noip2015 运输计划

noip2015 运输计划

题意

传送门

解法

我们考虑二分答案。我们二分操作后最长的长度为多少,然后看他能否办到。然后我们考虑m条路径中长度大于(要预处理长度)mid的路径,将它经过的路径标记起来,然后我们看是否有边被大于mid的所有边经过,然后再看最大值减去这条边的值是否小于等于mid就行了。
至于如何标记树上的边覆盖的边,树上差分一下就好了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#define INF 2139062143
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
    x=0;T k=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
}
const int maxn=3e5+15;
int fir[maxn],nxt[maxn*2],wi[maxn*2],to[maxn*2],ecnt;
void add_edge(int u,int v,int w) {
	nxt[++ecnt]=fir[u];fir[u]=ecnt;wi[ecnt]=w;to[ecnt]=v;
	nxt[++ecnt]=fir[v];fir[v]=ecnt;wi[ecnt]=w;to[ecnt]=u;
}

int dep[maxn],fa[maxn],sz[maxn],son[maxn],top[maxn],dfn;
int tot[maxn];

void dfs1(int u,int f) {
	fa[u]=f;sz[u]=1,dep[u]=dep[f]+1;son[u]=0;
	for(int e=fir[u];e;e=nxt[e]) {
		int v=to[e];
		if(v==f) continue;
		tot[v]=tot[u]+wi[e];
		dfs1(v,u);
		sz[u]+=sz[v];
		if(sz[v]>sz[son[u]]) son[u]=v;
	}
}

void dfs2(int u,int topf) {
	top[u]=topf;
	if(son[u]) dfs2(son[u],topf);
	for(int e=fir[u];e;e=nxt[e]) {
		int v=to[e];
		if(v==fa[u]||v==son[u]) continue;
		dfs2(v,v);
	}
}

int LCA(int x,int y) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	return x;
}

int n,m;
struct node {
	int u,v,len,lca;
}q[maxn];

int co[maxn];
void dfs(int u) {
	for(int e=fir[u];e;e=nxt[e]) {
		int v=to[e];
		if(v==fa[u]) continue;
		dfs(v);
		co[u]+=co[v];
	}
}

bool check(int sta) {
	del(co,0);int cnt=0,maxx=0;
	for(int i=1;i<=m;i++) {
		if(q[i].len>sta) {
			maxx=max(q[i].len,maxx);
			++co[q[i].v],++co[q[i].u];
			co[q[i].lca]-=2;
			++cnt;
		}
	}
	if(!cnt) return 1;
	dfs(1);
	for(int i=2;i<=n;i++) {
		if(co[i]==cnt&&maxx-(tot[i]-tot[fa[i]])<=sta) return 1;
	}
	return 0;
}

int main()
{
	read(n),read(m);
	int u,v,w;
	for(int i=1;i<n;i++) {
		read(u),read(v),read(w);
		add_edge(u,v,w);
	}
	dfs1(1,0);dfs2(1,1);
	int l=0,r=0;
	for(int i=1;i<=m;i++) {
		read(q[i].u),read(q[i].v);
		q[i].lca=LCA(q[i].u,q[i].v);
		q[i].len=tot[q[i].u]+tot[q[i].v]-2*tot[q[i].lca];
		r=max(r,q[i].len);
	}
	int ans;
	while(l<=r) {
		int mid=(l+r)>>1;
		if(check(mid)) {
			r=mid-1;ans=mid;
		}
		else l=mid+1;
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2018-10-04 17:23  Mr_asd  阅读(165)  评论(0)    收藏  举报