• 【uoj7】 NOI2014—购票


    http://uoj.ac/problem/7 (题目链接)

    题意

      给出一棵有根树,每次从一个节点出发可以买票到达它的一定范围内的祖先。问对于每一个点,到达根的最小花费是多少。

    Solution

      右转题解→_→:LCF

      一些细节自己YY一下就好,看看代码也行。

    细节

      最好写读入优化?

    代码

    // uoj7
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf (1ll<<60)
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    inline LL gi() {
    	LL x=0,f=1;char ch=getchar();
    	while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();}
    	while (ch<='9' && ch>='0') {x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int maxn=200010;
    int n,T,cnt,a[maxn],par[maxn],head[maxn];
    LL d[maxn],Q[maxn],P[maxn],L[maxn],ans[maxn];
    
    struct node {LL w;int num;}t[maxn];
    struct edge {int to,next;}e[maxn<<1];
    
    namespace DP {
    	int l,r,q[maxn];
    	void Clear() {l=1,r=0;}
    	double slope(int i,int j) {
    		return (double)(ans[i]-ans[j])/(d[i]-d[j]);
    	}
    	void push(int x) {
    		while (l<r && slope(q[r-1],q[r])<slope(x,q[r])) r--;
    		q[++r]=x;
    	}
    	void update(int x) {
    		if (l>r) return;
    		int ll=l,rr=r,y;
    		while (ll<=rr) {
    			int mid=(ll+rr)>>1;
    			if (ll<mid && slope(q[mid-1],q[mid])<P[x]) y=mid,rr=mid-1;
    			else if (rr>mid && slope(q[mid],q[mid+1])>P[x]) y=mid,ll=mid+1;
    			else {y=mid;break;}
    		}
    		y=q[y];
    		ans[x]=min(ans[x],ans[y]+(d[x]-d[y])*P[x]+Q[x]);
    	}
    }
    using namespace DP;
    
    namespace NodeDivide {
    	int size[maxn],f[maxn],vis[maxn];
    	int Dargen,sum,dfn;
    	bool cmp(node a,node b) {
    		return a.w>b.w;
    	}
    	void caldargen(int x,int fa) {
    		size[x]=1;f[x]=0;
    		for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) {
    				caldargen(e[i].to,x);
    				size[x]+=size[e[i].to];
    				f[x]=max(f[x],size[e[i].to]);
    			}
    		f[x]=max(f[x],sum-size[x]);
    		if (f[x]<f[Dargen]) Dargen=x;
    	}
    	void dfs(int x,int fa) {
    		a[++dfn]=x;
    		for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) dfs(e[i].to,x);
    	}
    	void work(int x) {
    		vis[x]=1;
    		if (!vis[par[x]]) {
    			sum=size[par[x]];
    			Dargen=0;caldargen(par[x],x);
    			work(Dargen);
    		}
    		Clear();
    		for (int j=par[x];!vis[j] && d[x]-d[j]<=L[x];j=par[j]) push(j);
    		update(x);
    		dfn=0;
    		for (int i=head[x];i;i=e[i].next)
    			if (!vis[e[i].to] && e[i].to!=par[x]) dfs(e[i].to,x);
    		for (int i=1;i<=dfn;i++) t[i]=(node){d[a[i]]-L[a[i]],a[i]};
    		sort(t+1,t+1+dfn,cmp);
    		Clear();
    		for (int j=x,i=1;i<=dfn;i++) {
    			for (;(!vis[j] || j==x) && t[i].w<=d[j];j=par[j]) push(j);
    			update(t[i].num);
    		}
    		for (int i=head[x];i;i=e[i].next) if (e[i].to!=par[x] && !vis[e[i].to]) {
    				sum=size[e[i].to],Dargen=0;
    				caldargen(e[i].to,x);
    				work(Dargen);
    			}
    		vis[x]=0;
    	}
    	void Init() {
    		f[Dargen=0]=1<<30;
    		sum=n;vis[0]=1;
    		caldargen(1,0);
    		work(Dargen);
    	}
    }
    
    void link(int u,int v) {
    	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
    	e[++cnt]=(edge){u,head[v]};head[v]=cnt;
    }
    int main() {
    	n=gi(),T=gi();
    	for (int i=2;i<=n;i++) {
    		par[i]=gi(),d[i]=gi(),P[i]=gi(),Q[i]=gi(),L[i]=gi();
    		d[i]+=d[par[i]];ans[i]=inf;link(i,par[i]);
    	}
    	NodeDivide::Init();
    	for (int i=2;i<=n;i++) printf("%lld
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    阻塞赋值和非阻塞赋值
    组合逻辑和时序逻辑
    信道估计常用算法
    Verilog有限状态机FSM
    希尔伯特变换
    微信小程序取消分享的两种方式
    orm 常用字段
    drf获取请求过来时的request
    WeChat--API
    Django之admin源码浅析
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6382745.html
Copyright © 2020-2023  润新知