NOIP2015 运输计划 树链剖分 差分 二分

//VFK出的题目,还是比较有水平的,倒是不卡常数
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 300000 + 5;
const int INF = 0x7f7f7f7f;
int fst[MAXN],next[MAXN<<1],len[MAXN<<1],to[MAXN<<1],ec=0;
inline void add(int u,int v,int w)
{
	to[++ec]=v;
	len[ec]=w;
	next[ec]=fst[u];
	fst[u]=ec;
}
int son[MAXN],size[MAXN],fa[MAXN],dep[MAXN],w[MAXN];
int dfn[MAXN],top[MAXN],s[MAXN],dfs_clock=0;
void dfs()
{
	int cur[MAXN];
	int tmp[MAXN],roof=0;//stack;
	memcpy(cur,fst,sizeof(fst));
	dep[1]=1;size[1]=1;son[1]=0;fa[1]=0;w[1]=0;
	tmp[roof++]=1;
	while(roof)
	{
		int u=tmp[roof-1];
		if(cur[u])
		{
			int &e=cur[u];
			int v=to[e];
			if(v!=fa[u])
			{
				w[v]=len[e];
				dep[v]=dep[u]+1;
				fa[v]=u;
				tmp[roof++]=v;
				size[v]=1;
				son[v]=0;
			}
			e=next[e];
		}
		else
		{
			for(register int i=fst[u];i;i=next[i])
			{
				int v=to[i];
				if(v!=fa[u])
				{
					size[u]+=size[v];
					if(size[son[u]]<size[v])son[u]=v;	
				}
			}
			roof--;
		}		
	}
	if(roof!=0)printf("error\n");
	bool vis[MAXN];
	memset(vis,0,sizeof(vis));
	memcpy(cur,fst,sizeof(fst));
	dfs_clock=0;
	dfn[1]=++dfs_clock;
	s[dfs_clock]=s[dfs_clock-1]+w[1];
	top[1]=1;
	tmp[roof++]=1;
	vis[1]=true;
	while(roof)
	{
		int u=tmp[roof-1];
		if(son[u] && !vis[son[u]])
		{
			int v=son[u];
			tmp[roof++]=v;
			dfn[v]=++dfs_clock;
			s[dfs_clock]=s[dfs_clock-1]+w[v];
			top[v]=top[u];
			vis[v]=true;
		}
		else if(cur[u])
		{
			int v=to[cur[u]];
			if(!vis[v])//v!=fa[u]
			{
				tmp[roof++]=v;
				vis[v]=true;
				dfn[v]=++dfs_clock;
				s[dfs_clock]=s[dfs_clock-1]+w[v];
				top[v]=v;
			}
			cur[u]=next[cur[u]];
		}
		else roof--;
	}
}
inline int road(int l,int r){return s[r]-s[l-1];}
int path(int u,int v)
{	
	if(u==v)return 0;
	int ans=0;
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		ans+=road(dfn[top[u]],dfn[u]);
		u=fa[top[u]];
	}
	if(dep[u]>dep[v])swap(u,v);
	ans+=road(dfn[son[u]],dfn[v]);///son u
	return ans;
}
int n,m;
int in()
{
	int c=getchar(),x=0;
	while(c<'0'||c>'9')c=getchar();
	while(c<='9'&&c>='0')
	{
		x=x*10+c-'0';
		c=getchar();
	}
	return x;
}
struct plan{int u,v,w;}p[MAXN];
bool cmp(plan a,plan b){return a.w>b.w;}
int delta[MAXN];
inline void update(int l,int r)
{
	delta[l]++;
	delta[r+1]--;
}
void modify(int u,int v)
{
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		update(dfn[top[u]],dfn[u]);
		u=fa[top[u]];
	}
	if(dep[u]>dep[v])swap(u,v);
	update(dfn[son[u]],dfn[v]);son u
}
bool check(int x)
{
	memset(delta,0,sizeof(delta));
	int cnt_p=0,expt=0;
	for(register int i=1;i<=m;i++)
	{
		if(p[i].w<=x)break;
		cnt_p++;
		expt=max(expt,p[i].w-x);
		modify(p[i].u,p[i].v);
	}
	int cnt_e=0,mxp=0;
	for(register int i=1;i<=n;i++)//i==dfn[u]
	{
		cnt_e+=delta[i];
		if(cnt_e==cnt_p)mxp=max(mxp,road(i,i));
	}
	return mxp>=expt;
}
int main()
{
	n=in();
	m=in();
	for(register int i=1;i<=n-1;i++)
	{
		int a=in(),b=in(),t=in();
		add(a,b,t);
		add(b,a,t);
	}
	dfs();
	int l=0,r=0;
	for(register int i=1;i<=m;i++)
	{
		p[i].u=in();
		p[i].v=in();
		p[i].w=path(p[i].u,p[i].v);
		r=max(r,p[i].w);
	}
	sort(p+1,p+1+m,cmp);
	int ans=0;
	//printf("r=%d\n",r);
	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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值