zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    HDOJ 2095 find your present (2)
    HDOJ 2186 悼念512汶川大地震遇难同胞——一定要记住我爱你
    九度 1337 寻找最长合法括号序列
    九度 1357 疯狂地Jobdu序列
    HDOJ 1280 前m大的数
    九度 1343 城际公路网
    九度 1347 孤岛连通工程
    HDOJ 2151 Worm
    九度 1342 寻找最长合法括号序列II
    九度 1346 会员积分排序
  • 原文地址:https://www.cnblogs.com/acha/p/6360445.html
Copyright © 2011-2022 走看看