[NOI2014] 购票
2021/5/23 10:28:56
本文主要是介绍[NOI2014] 购票,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
这题怎么大家都做过了/kk
感谢 Fz 的题解!
首先这题有一个 DP 式子,
\[f_i = d_i \times p_i + q_i +\min(-d_j\times p_i+f_j) \]明显是斜率优化的形式。
但对于 \(u\) 有贡献的只有离他较近的若干个祖先。
这里就有几个做法;
- 点分
- 树剖,u 到某个祖先可以剖为 若干条重链的前缀 + 一条重链的中间一段,然后丢在重链上处理。
- 在 dfs 的过程中,维护一个可撤销的单调栈(用来维护凸包)
- 一种巧妙的做法:首先 dfs ,在每个点 dfs 出去的时候记上时间戳,可以得到出栈序。dfs DP 的时候,维护一个线段树套李超树(或者单调栈维护凸包也行),每次到 u 时,查询的就是 [ u 的出栈序 到 那个祖先的出栈序 ] 这一段区间的点,进行转移。
这种方法也许在处理其他题(从上到下的查询?)时也有用。
贺来的代码
#include<bits/stdc++.h> #define For(i,a,b) for(register int i=(a);i<=(b);++i) #define Rep(i,a,b) for(register int i=(a);i>=(b);--i) #define int long long using namespace std; inline int read() { char c=getchar();int x=0;bool f=0; for(;!isdigit(c);c=getchar())f^=!(c^45); for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48); if(f)x=-x;return x; } #define fi first #define se second #define pb push_back #define mkp make_pair typedef pair<int,int>pii; typedef vector<int>vi; #define maxn 200005 #define N 4000005 int n; vector<int>e[maxn]; int k[maxn],b[maxn],cnt,rt[maxn<<2]; inline int f(int id,int x){return k[id]*x+b[id];} int tag[N],ls[N],rs[N]; void upd(int&p,int l,int r,int x) { if(!p)p=++cnt; if(!tag[p])return tag[p]=x,void(); int mid=l+r>>1; if(f(x,mid)<f(tag[p],mid))swap(x,tag[p]); if(l<r) k[x]<k[tag[p]]?upd(rs[p],mid+1,r,x):upd(ls[p],l,mid,x); } int qry(int p,int l,int r,int x) { if(!p)return 1e18; int mid=l+r>>1; return min(f(tag[p],x),x<=mid?qry(ls[p],l,mid,x):qry(rs[p],mid+1,r,x)); } void modify(int p,int l,int r,int x,int v) { upd(rt[p],0,1e6,v); if(l==r)return; int mid=l+r>>1; x<=mid?modify(p<<1,l,mid,x,v):modify(p<<1|1,mid+1,r,x,v); } int ask(int p,int l,int r,int ql,int qr,int v) { if(l>=ql&&r<=qr)return qry(rt[p],0,1e6,v); int mid=l+r>>1,res=1e18; if(ql<=mid)res=min(res,ask(p<<1,l,mid,ql,qr,v)); if(qr>mid)res=min(res,ask(p<<1|1,mid+1,r,ql,qr,v)); return res; } int o[maxn],idx; void getO(int u){ for(auto v:e[u])getO(v); o[u]=++idx; } int s[maxn],p[maxn],q[maxn],l[maxn],fa[maxn]; int dp[maxn],dis[maxn],top,id[maxn]; void dfs(int u) { k[u]=-dis[top],b[u]=dp[u]; id[top]=u; modify(1,1,n,o[u],u); for(auto v:e[u]){ ++top,dis[top]=dis[top-1]+s[v]; int anc=id[lower_bound(dis,dis+top,dis[top]-l[v])-dis]; dp[v]=ask(1,1,n,o[v],o[anc],p[v]); dp[v]=dp[v]+dis[top]*p[v]+q[v]; dfs(v); --top; } } signed main() { n=read(),read(); For(i,2,n){ fa[i]=read(),s[i]=read(),p[i]=read(),q[i]=read(),l[i]=read(); e[fa[i]].pb(i); } getO(1); dfs(1); For(i,2,n)printf("%lld\n",dp[i]); return 0; }
这篇关于[NOI2014] 购票的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-15JavaMailSender是什么,怎么使用?-icode9专业技术文章分享
- 2024-11-15JWT 用户校验学习:从入门到实践
- 2024-11-15Nest学习:新手入门全面指南
- 2024-11-15RestfulAPI学习:新手入门指南
- 2024-11-15Server Component学习:入门教程与实践指南
- 2024-11-15动态路由入门:新手必读指南
- 2024-11-15JWT 用户校验入门:轻松掌握JWT认证基础
- 2024-11-15Nest后端开发入门指南
- 2024-11-15Nest后端开发入门教程
- 2024-11-15RestfulAPI入门:新手快速上手指南