P2305 [NOI2014] 购票
考虑动态规划:
设置状态 \(f_i\) 表示从 \(i\) 到 \(1\) 所需的最少资金。
则有状态转移(\(j\) 为 \(i\) 的祖先): \(f_i = \min_{d_i-d_j \leq l_i}{f_j + (d_i-d_j)\cdot p_i+q_i}\).
对式子进行简化,变为 \(f_i = \min_{d_i-d_j \leq l_i}{(f_j-d_j\cdot p_i)}+d_i\cdot p_i + q_i\).
- 若不考虑距离限制,则可以用李超线段树协助转移,时间复杂度 \(\mathcal{O(n\log n)}.\)
- 考虑一条链的情况,此时加上距离限制,可以用线段树套李超来解决,时间复杂度 \(\mathcal{O(n \log ^2 n)}\)。
由以上两个特殊情况,推到普遍情况。
考虑运用出栈序解决树的情况,出栈序即离开每个节点返回祖先的顺序。
我们可以发现出栈序的特殊性质:
对于一个点 \(u\),它的祖先表示为 \(fa\),则 \(dfn_u\) 和 \(dfn_{fa}\) 之间的所有点,要不没遍历过,要不就是 \(u\) 到 \(fa\) 路径上的点。
这个特殊性质很容易理解,画一画图就可以了。
于是就可以转化为链的情况,用树套树解决问题。
#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
using namespace std;
const int N = 2e5+5;
inline ll read() {
ll x = 0; char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x*10 + c-'0', c = getchar();
return x;
}
namespace LC {
struct segment{
ll k,b;
int p;
ll operator ()(ll x){
return k*x+b;
}
}tr[N*20];
int ls[N*20],rs[N*20];
int idx=0;
void Ins(int &u,int l,int r,segment t){
if(!u){
u=++idx;
tr[u]=t;
return ;
}
int mid=l+r>>1;
if(t(mid)<tr[u](mid))swap(tr[u],t);
if(l>=r)return ;
if(t.k<tr[u].k) Ins(rs[u],mid+1,r,t);
else Ins(ls[u],l,mid,t);
}
ll qry(int u,int l,int r,int pos){
if(!u)return 1e18;
ll res=tr[u](pos);
int mid=l+r>>1;
if(pos<=mid)res=min(res,qry(ls[u],l,mid,pos));
else res=min(res,qry(rs[u],mid+1,r,pos));
return res;
}
}
struct Edge{
int to,nxt;
}e[N];
int tot=0,head[N];
void add_Edge(int u,int v){
e[tot].nxt=head[u];
e[tot].to=v;
head[u]=tot++;
}
int n,m,top;
int fa[N];
int stk[N],b[N];
ll d[N],f[N],s[N],l[N],p[N],q[N];
#define ls u<<1
#define rs u<<1|1
struct Tree{
int rt;
}tr[N<<2];
void update(int u,int l,int r,int pos,LC::segment t){
LC::Ins(tr[u].rt,0,1e6,t);
if(l==r)return ;
int mid=l+r>>1;
if(pos<=mid)update(ls,l,mid,pos,t);
else update(rs,mid+1,r,pos,t);
}
ll query(int u,int l,int r,int L,int R,int x){
if(L<=l && r<=R)return LC::qry(tr[u].rt,0,1e6,x);
int mid=l+r>>1;
if(L>mid)return query(rs,mid+1,r,L,R,x);
if(R<=mid)return query(ls,l,mid,L,R,x);
return min(query(ls,l,mid,L,R,x),query(rs,mid+1,r,L,R,x));
}
void dfs(int u) {
// cout<<u<<"\n";
for(int i=head[u];~i;i=e[i].nxt) {
int v=e[i].to;
dfs(v);
}
b[u]=++top;
}
void DFS(int u){
LC::segment t={-d[top],f[u],u};
stk[top]=u;
update(1,1,n,b[u],t);
// cout<<b[u]<<"\n";
for(int i=head[u];~i;i=e[i].nxt) {
int v=e[i].to;
top++;
d[top]=d[top-1]+s[v];
int x=lower_bound(d,d+top,d[top]-l[v])-d;
// cout<<d[top]-l[v]<<'\n';
int ql=b[v],qr=b[stk[x]];
// cout<<ql<<" "<<qr<<"\n";
f[v]=query(1,1,n,ql,qr,p[v])+d[top]*p[v]+q[v];
DFS(v);
top--;
}
}
int main() {
// freopen("P2305_4.in","r",stdin);
// freopen("1.out","w",stdout);
n=read(),m=read();
memset(head,-1,sizeof(head));
for(int i=2;i<=n;i++){
fa[i]=read(),s[i]=read(),p[i]=read(),q[i]=read(),l[i]=read();
add_Edge(fa[i],i);
}
dfs(1);
top=tot=0;
DFS(1);
for(int i=2;i<=n;i++)
printf("%lld\n",f[i]);
return 0;
}

浙公网安备 33010602011771号