xsy 1790 - 不回头的旅行

from NOIP2016模拟题28

Description

一辆车,开始没油,可以选择一个点(加油站)出发
经过一个点i可加g[i]的油,走一条边减少len的油
没油的时候车就跪了
特别的,跪在加油站上可以加油继续走
给出一棵树,求最多可以走过多少个点

Analysis

点分治很明显的,只是dfs要点技巧
求出从根往下走到某个点的深度及需要的油
求出从某个点往上走到根的深度及提供的油
注意要同样的两个端点,不同方向走答案不同
所以点分时要扫两次

向下

每个点到根的消耗/剩余会长得像心电图

我们只要保证最低点>=0就好

向上

我们记录一个mx表示每个点到上一个可到根的点的消耗/剩余
每次从mx=0的可到根点x出发会经过如图

轨迹到达下一个mx>=0的点
则那个点可以到x
(旋转180°,改下0点)就变成从下面出发了
同时要把mx变回0

Code

#include <cstdio>
#include <cstdlib>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
const int INF=2147483647;
const int M=100007;

inline int rd(){
	int x=0;bool f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
	for(;isdigit(c);c=getchar()) x=x*10+c-48;
	return f?x:-x;
}

int n;
int val[M];

int g[M],te;
struct edge{int y,d,next;}e[M<<1];
void addedge(int x,int y,int z){
	e[++te].y=y;e[te].d=z;e[te].next=g[x];g[x]=te;
}

struct node{
	int y,d;
	node(int yy=0,int dd=0){y=yy;d=dd;}
}que[M];
int tq;

int vis[M];
int sz[M];
int mi,size,rt;
int a[M];

int ans=0;

void getsz(int x,int fa){
	sz[x]=1;
	int p,y;
	for(p=g[x];p;p=e[p].next)
	if(!vis[y=e[p].y]&&y!=fa){
		getsz(y,x);
		sz[x]+=sz[y];
	}
}

void getrt(int x,int fa){
	int f,p,y;
	f=size-sz[x];
	for(p=g[x];p;p=e[p].next)
	if(!vis[y=e[p].y]&&y!=fa){
		getrt(y,x);
		f=max(f,sz[y]);
	}
	if(f<mi) mi=f,rt=x;
}

void find(int dep,int supply){
	int l=1,r=size,mid;
	while(l<r){
		mid=(l+r)/2 +1;
		if(a[mid]<=supply) l=mid;
		else r=mid-1;
	}
	ans=max(ans,l+dep);
}

void getup(int x,int fa,int dep,int nw,int mn){
	if(mn>=0){
		find(dep,nw);
		mn=0;
	}
	int p,y;
	for(p=g[x];p;p=e[p].next)
	if(!vis[y=e[p].y]&&y!=fa)
		getup(y,x,dep+1,nw+val[y]-e[p].d, mn+val[y]-e[p].d);
}

void getdw(int x,int fa,int dep,int nw,int mn){
	mn=min(mn,nw);
	a[dep]=min(a[dep],-min(mn,0));
	int p,y;
	for(p=g[x];p;p=e[p].next)
	if(!vis[y=e[p].y]&&y!=fa)
		getdw(y,x,dep+1,nw+val[x]-e[p].d, mn);
}

void calc(int x){
	int i,j,p,y,d;
	
	getsz(x,0);
	
	tq=0;
	for(p=g[x];p;p=e[p].next)
	if(!vis[y=e[p].y]) que[++tq]=node(e[p].y,e[p].d);
	
	for(i=1;i<=sz[x]+1;i++) a[i]=INF;
	a[1]=0;
	for(i=1;i<=tq;i++){
		y=que[i].y; d=que[i].d;
		getup(y,0,1,val[y]-d,val[y]-d);
		getdw(y,0,2,val[x]-d,INF);
		for(j=sz[y]+1;j>0;j--) a[j]=min(a[j],a[j+1]);
	}
	
	for(i=1;i<=sz[x]+1;i++) a[i]=INF;
	a[1]=0;
	for(i=tq;i>=1;i--){
		y=que[i].y; d=que[i].d;
		getup(y,0,1,val[y]-d,val[y]-d);
		getdw(y,0,2,val[x]-d,INF);
		for(j=sz[y]+1;j>0;j--) a[j]=min(a[j],a[j+1]);
	}
}

void work(int fr){
	getsz(fr,0);
	mi=size=sz[fr];
	getrt(fr,0);
	int x=rt,p,y;
	vis[x]=1;
	calc(x);
	for(p=g[x];p;p=e[p].next)
	if(!vis[y=e[p].y]){
		work(y);
	}
}

int main(){
	int i,x,y,z;
	n=rd();
	for(i=1;i<=n;i++) val[i]=rd();
	for(i=1;i<n;i++){
		x=rd(),y=rd(),z=rd();
		addedge(x,y,z);
		addedge(y,x,z);
	}
	work(1);
	printf("%d\n",ans);
	return 0;
}
posted @ 2017-02-03 18:40  _zwl  阅读(124)  评论(0编辑  收藏  举报