P2305 [NOI2014]购票
生活随笔
收集整理的這篇文章主要介紹了
P2305 [NOI2014]购票
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
P2305 [NOI2014]購票
題目描述
詳見:P2305?[NOI2014]購票
Solution
寫出一個樸素的DP可以看出顯然是一個斜率優化,且是在樹上求解答案。
因此用點分治維護樹上斜率優化DP。
設現在的重心為,根為,我們需要先遞歸處理所在的連通塊。
接下來用? ?? 的路徑上的值更新下面的點。
按這些點可以到達的最淺祖先的深度排序,依次加入新點,斜率優化維護,二分凸包求解答案即可。
時間復雜度? ?。
Code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=2e5+50; const int INF=0x3f3f3f3f; const ll loo=1ll<<60; double slope[MAXN]; struct enode{ll to,nxt,c; } e[MAXN<<1]; ll edgenum=0,smin,root,num,top; ll st[MAXN],size[MAXN],vis[MAXN],dis[MAXN],f[MAXN],E[MAXN],head[MAXN],p[MAXN],q[MAXN],l[MAXN],fa[MAXN]; inline ll read() {ll x=0,f=1; char c=getchar();while (c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f; } void add_edge(int u,int v,ll c) { e[++edgenum]=(enode){v,head[u],c}; head[u]=edgenum; } void get_dis(int x) { for (int i=head[x];i!=-1;i=e[i].nxt) dis[e[i].to]=dis[x]+e[i].c,get_dis(e[i].to); } void get_root(int x,int Size) {size[x]=1; ll mx=0;for (int i=head[x];i!=-1;i=e[i].nxt)if (!vis[e[i].to]){get_root(e[i].to,Size);size[x]+=size[e[i].to];mx=max(mx,size[e[i].to]);}mx=max(mx,Size-size[x]);if (smin>=mx) root=x,smin=mx; } void build(int x) {E[++num]=x;for (int i=head[x];i!=-1;i=e[i].nxt) if (!vis[e[i].to]) build(e[i].to); } double slp(int x,int y){ return (1.0*f[y]-f[x])/(1.0*dis[y]-dis[x]); } int compareE(int x,int y){ return dis[x]-l[x]>dis[y]-l[y]; } void insert(int x) {while (top>=2&&slope[top-1]<=slp(st[top],x)) top--;st[++top]=x,slope[top]=-1e18,slope[top-1]=slp(st[top-1],st[top]); } ll query(double x) {ll l=1,r=top,ans;while (l<=r){ll mid=(l+r)>>1;if (slope[mid]<=x) ans=mid,r=mid-1;else l=mid+1;}return st[ans]; } void solve(int x,int Size) {if (Size==1) return;root=smin=INF;get_root(x,Size);ll rt=root,mx=smin;for (int i=head[rt];i!=-1;i=e[i].nxt) vis[e[i].to]=1,Size-=size[e[i].to];//cout<<Size<<" "<<rt<<" "<<mx<<endl;solve(x,Size);num=0;for (int i=head[rt];i!=-1;i=e[i].nxt) build(e[i].to);sort(E+1,E+num+1,compareE);top=0;for (int i=1,j=rt;i<=num;i++){while (j!=fa[x]&&dis[j]>=dis[E[i]]-l[E[i]]) insert(j),j=fa[j];if (top){int k=query(p[ E[i] ]);f[ E[i] ]=min(f[ E[i] ],f[k]+(dis[ E[i] ]-dis[k])*p[ E[i] ]+q[ E[i] ]);}}for (int i=head[rt];i!=-1;i=e[i].nxt) solve(e[i].to,size[e[i].to]); } int main() {int n=read(),t=read();for (int i=1;i<=n;i++) head[i]=-1;for (int i=2;i<=n;i++) {int u=read(),c=read(); p[i]=read(),q[i]=read(),l[i]=read(),f[i]=loo;add_edge(u,i,c); fa[i]=u;} get_dis(1);solve(1,n);for (int i=2;i<=n;i++) printf("%lld\n",f[i]);return 0; }?
總結
以上是生活随笔為你收集整理的P2305 [NOI2014]购票的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 笔记本电脑保养小技巧新笔记本电脑如何保养
- 下一篇: P5327 [ZJOI2019]语言