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;
    }
    
  • 相关阅读:
    Oracle修改字段类型
    JS解析JSON字符串
    C#Json转DataTable
    解决前台和后台传值出现中文乱码
    Oracle 存储过程简单语法
    EasyUI 冻结列
    EasyUI 数据网格行过滤
    windows计划任务
    C#日志文件
    bat 读取 ini 配置文件
  • 原文地址:https://www.cnblogs.com/acha/p/6360445.html
Copyright © 2011-2022 走看看