【NOIP2015提高组】运输计划

更新!

表示之前的方法只能过95分的数据。最后一个会T飞~
所以,经过努力的奋斗,我终于过了!!

解法一:

这题我们要求最值,可以考虑二分答案。
二分答案,如何判断能否在mid的时间内完成呢?
我们可以用差分。将那些物流时间>mid的链(设有tot条,其中最多比mid它maxx)加入差分数组中,
然后将整个树遍历一遍,我们对于每一条边看看它有没有tot条经过且这条边的时间>=maxx。
如果有,那么OK,反之。
然后,我们来看看如何来求LCA。
简单!倍增啊!可惜倍增不行。。。TLE95分
然后我们只好打tarjan_LCA或神奇(竟然能过?!)的树链剖分LCA了。
只要代码打的不是很丑,应该都能A了。
解法二暂时不提供(作者没打。。。)

Code

#include
#include
#include
#define N 300010
using namespace std;
struct node{int v,fr,t;}e[N<<1],g[N<<1];
int tail[N],head[N],dep[N],fat[N],ti[N],fa[N];
int a[N][4],o[N],t[N],cnt=0,cnt1=0;
int n,m,l=0,r=0,mid,len,gr;
bool bz[N];

inline int read()
{
	int x=0; char c=getchar();
	while (c<'0' || c>'9') c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}

void add(int u,int v,int t) {e[++cnt]=(node){v,tail[u],t}; tail[u]=cnt;}

void add1(int u,int v,int t) {g[++cnt1]=(node){v,head[u],t}; head[u]=cnt1;}

void dfs(int x)
{
	o[++o[0]]=x;
	for (int p=tail[x],v;p;p=e[p].fr)
	{
		v=e[p].v;
		if (fat[v]) continue;
		dep[v]=dep[x]+1,fat[v]=x;
		ti[v]=ti[x]+e[p].t,dfs(v);
	}
}

int gf(int x) {return !fa[x] ? x:fa[x]=gf(fa[x]);}

void tarjan(int x)
{
	for (int p=head[x],v,fr;p;p=g[p].fr)
	{
		v=g[p].v;
		if (!bz[v]) continue;
		fr=g[p].t;
		a[fr][3]=gf(v);
		a[fr][2]=ti[x]+ti[v]-(ti[a[fr][3]]<<1);
		r=max(r,a[fr][2]); 
	}
	for (int p=tail[x],v;p;p=e[p].fr)
	{
		v=e[p].v;
		if (bz[v]) continue;
		bz[v]=1,tarjan(v),fa[v]=x;
	}
}

bool pd(int x)
{
	int maxx=0,tot=0;
	memset(t,0,sizeof(t));
	for (int i=1;i<=m;i++)
		if (a[i][2]>x)
		{
			t[a[i][0]]++,t[a[i][1]]++,tot++;
			t[a[i][3]]-=2,maxx=max(maxx,a[i][2]-x);
		}
	for (int i=o[0];i>0;i--)
		t[fat[o[i]]]+=t[o[i]];
	for (int i=1;i<=n;i++)
		if (t[i]==tot && ti[i]-ti[fat[i]]>=maxx) return 1;
	return 0;
}

int main()
{
	freopen("transport.in","r",stdin);
//	freopen("transport.out","w",stdout);
	n=read(),m=read();
	for (int i=1,u,v,t;i<n;i++)
	{
		u=read(),v=read(),t=read();
		add(u,v,t),add(v,u,t);
	}
	dfs(1);
	for (int i=1;i<=m;i++)
	{
		a[i][0]=read(),a[i][1]=read();
		add1(a[i][0],a[i][1],i),add1(a[i][1],a[i][0],i);
	}
	tarjan(1); 
	while (l<=r)
	{
		mid=l+r>>1;
		if (pd(mid)) r=mid-1;
		else l=mid+1;
	}
	printf("%d\n",l);
	return 0;
}

你可能感兴趣的:(NOIP,倍增LCA)