• P2305 [NOI2014] 购票


    题意

    略。

    分析

    容易列出 (dp) 方程,然后因为我们子节点是由祖先节点转移,所以这样的情况我们可以考虑出栈序。

    出栈序的性质就是对于一个节点来说,其祖先节点的出栈序都在这个节点的后面,于是我们可以考虑dfs序更新,那么所有这个点后面的数都只有它的祖宗才有值,于是就是维护后缀了。

    这里维护区间可以线段树套李超线段树,也是经典做法。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define int long long
    #define ll long long
    const int N=2e6+5,INF=1e18,MOD=99824353;
    const ll M=1e6;
    int n,t,dfn[N],rev[N],DFN;
    ll p[N],q[N],l[N],dep[N];
    int head[N],to[N],nex[N],val[N],idx;
    inline void add(int u,int v,int w){nex[++idx]=head[u];to[idx]=v;val[idx]=w;head[u]=idx;return ;}
    int fa[N][21];
    int Querypos(int x,int lim){
    	int u=x;
    	for(int i=20;i>=0;i--) if(dep[x]-dep[fa[u][i]]<=lim) u=fa[u][i];
    	return u;
    }
    void dfs(int x){
    	for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    	for(int i=head[x];i;i=nex[i]) dep[to[i]]=dep[x]+val[i],dfs(to[i]);
    	dfn[x]=++DFN;rev[DFN]=x;
    	return ;
    }
    int root[N<<2],ls[N<<2],rs[N<<2],tag[N<<2],cur,cnt;
    ll Ans[N],k[N],b[N];
    inline ll calc(int id,ll x){return k[id]*x+b[id];}
    void Modify(int &x,ll l,ll r,int v){
    //	cout<<"!";
    	if(!x) x=++cur;
    	if(!tag[x]) return tag[x]=v,void();
    	if(l==r){if(calc(tag[x],l)>calc(v,l)) tag[x]=v;return ;}
    	ll mid=l+r>>1,Q1=calc(tag[x],mid),Q2=calc(v,mid);
    	if(Q1>Q2){
    		if(k[tag[x]]>k[v]) Modify(ls[x],l,mid,tag[x]),tag[x]=v;
    		else Modify(rs[x],mid+1,r,tag[x]),tag[x]=v;
    	}
    	else{
    		if(k[tag[x]]>k[v]) Modify(rs[x],mid+1,r,v);
    		else Modify(ls[x],l,mid,v);
    	}
    	return ;
    }
    ll Query(int x,ll l,ll r,ll pos){
    	if(!x) return INF;
    	if(l==r) return calc(tag[x],pos);
    	ll mid=l+r>>1,res=calc(tag[x],pos);
    	if(pos<=mid) return min(res,Query(ls[x],l,mid,pos));
    	return min(res,Query(rs[x],mid+1,r,pos));
    }
    ll Query(int x,int l,int r,int ql,int qr,ll val){
    	if(ql<=l&&r<=qr) return Query(root[x],0,M,val);
    	int mid=l+r>>1;ll res=INF;
    	if(ql<=mid) res=Query(x<<1,l,mid,ql,qr,val);
    	if(qr>mid) res=min(res,Query(x<<1|1,mid+1,r,ql,qr,val));
    	return res;
    } 
    void Modify(int x,int l,int r,int pos,int v){
    	Modify(root[x],0,M,v);
    	if(l==r) return ;
    	int mid=l+r>>1;
    	if(pos<=mid) Modify(x<<1,l,mid,pos,v);
    	else Modify(x<<1|1,mid+1,r,pos,v);
    }
    void DP(int x){
    	if(x==1){
    		k[++cnt]=0,b[cnt]=0;
    		Modify(1,1,n,dfn[1],cnt);
    	}
    	else{
    		Ans[x]=Query(1,1,n,dfn[x],dfn[Querypos(x,l[x])],p[x])+dep[x]*p[x]+q[x];
    		k[++cnt]=-dep[x],b[cnt]=Ans[x];
    		Modify(1,1,n,dfn[x],cnt);
    	}
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		DP(y);
    	}
    	return ;
    }
    signed main(){
    	read(n),read(t);
    	for(int i=2;i<=n;i++){
    		int f,v;
    		read(f),read(v),read(p[i]),read(q[i]),read(l[i]);
    		add(f,i,v);fa[i][0]=f;
    	}
    	dep[0]=-INF;
    	dfs(1);DP(1);
    	for(int i=2;i<=n;i++) write(Ans[i]),putchar('
    ');
    	return 0;
    }
    
  • 相关阅读:
    MutationObserverAPI--微任务
    Promise.then方法的执行顺序例题分析
    遍历器Iterator--指针对象
    最实用的数组去重方法
    【JavaScript】允许IE8使用placeholder
    【JavaScript】创建命名空间,Class,LOG
    【JavaScript】JavaScript模拟Class
    【Java】PrettyTime
    【JavaScript】日期和数字格式化
    前端开发总结
  • 原文地址:https://www.cnblogs.com/Akmaey/p/15032060.html
Copyright © 2020-2023  润新知