bzoj3672/luogu2305 购票 (运用点分治思想的树上cdq分治+斜率优化dp)

Posted ressed

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3672/luogu2305 购票 (运用点分治思想的树上cdq分治+斜率优化dp)相关的知识,希望对你有一定的参考价值。

我们都做过一道题(?)货币兑换,是用cdq分治来解决不单调的斜率优化

现在它放到了树上..

总之先写下来dp方程,$f[i]=min{f[j]+(dis[i]-dis[j])*p[i]+q[i]} ,j是i的祖先,dis[i]-dis[j]<=l[i]$ ,其中dis[i]表示1号点到i号点的距离

可以很明显的看出斜率优化,但我们要放到树上做

于是就运用点分治的思想来找重心(正如普通的cdq是找重点一样)

步骤是这样的:

1.对于根为x的一个子树,我们先找到它的重心rt

2.把rt的子树刨掉,但留下rt,然后递归地再做x,目的是先算出祖先们的答案,为更新孩子们做准备

3.把rt在子树x中的祖先按深度排序,把rt的子树(不包括rt)按照它们最远能到的祖先的深度排序,然后一边插祖先维护一个凸包,一边给孩子统计答案

4.递归地做rt的子节点

斜率优化的细节就不写了(因为全是蒙出来的)

  1 #include<bits/stdc++.h>
  2 #define pa pair<int,int>
  3 #define ll long long
  4 using namespace std;
  5 const int maxn=2e5+10,inf=0x3f3f3f3f;
  6 
  7 inline ll rd(){
  8     ll x=0;char c=getchar();int neg=1;
  9     while(c<0||c>9){if(c==-) neg=-1;c=getchar();}
 10     while(c>=0&&c<=9) x=x*10+c-0,c=getchar();
 11     return x*neg;
 12 }
 13 
 14 struct Edge{
 15     int b,ne;ll l;
 16 }eg[maxn*2];
 17 int fa[maxn][20],egh[maxn],ect;
 18 int N,NN,dep[maxn],ldep[maxn];
 19 int siz[maxn],root;
 20 int cnt[maxn],tmpl[maxn],tmpr[maxn],pct;
 21 int stk[maxn];
 22 ll dp[maxn],dis[maxn],p[maxn],q[maxn],l[maxn];
 23 bool vis[maxn];
 24 
 25 void dfs1(int x){
 26     int i;
 27     for(i=1;fa[x][i-1]&&fa[fa[x][i-1]][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1];
 28     int y=x;for(ll j=l[x];i>=0;i--){
 29         if(fa[y][i]&&dis[y]-dis[fa[y][i]]<=j)
 30             j-=dis[y]-dis[fa[y][i]],y=fa[y][i];
 31     }
 32     if(y!=x) ldep[x]=dep[y];
 33     else ldep[x]=-1;
 34     
 35     for(i=egh[x];i;i=eg[i].ne){
 36         int b=eg[i].b;
 37         dis[b]=dis[x]+eg[i].l;
 38         dep[b]=dep[x]+1;
 39         dfs1(b);
 40     }
 41 }
 42 
 43 void getroot(int x,int smsiz,int &ms,int &root){
 44     siz[x]=1;int mm=0;
 45     for(int i=egh[x];i;i=eg[i].ne){
 46         int b=eg[i].b;if(vis[b]) continue;
 47         getroot(b,smsiz,ms,root);siz[x]+=siz[b];
 48         mm=max(mm,siz[b]);
 49     }mm=max(mm,smsiz-siz[x]);
 50     if(mm<=ms) ms=mm,root=x;
 51 }
 52 void getson(int x){
 53     tmpr[++pct]=x;
 54     for(int i=egh[x];i;i=eg[i].ne){
 55         int b=eg[i].b;if(vis[b]) continue;
 56         getson(b);
 57     }
 58 }
 59 
 60 inline bool cmp(int a,int b){
 61     return ldep[a]>ldep[b];
 62 }
 63 
 64 inline double getk(int a,int b){
 65     return (double)(dp[a]-dp[b])/(dis[a]-dis[b]);
 66 }
 67 
 68 void cdq(int x,int s){
 69     if(s<=1) return;
 70     int rt,ms=inf;
 71     getroot(x,s,ms,rt);
 72     if(x!=rt){
 73         int sms=s,mmm=inf;
 74         for(int i=egh[rt];i;i=eg[i].ne) vis[eg[i].b]=1,sms-=siz[eg[i].b];
 75         cdq(x,sms);
 76     }int l=0;
 77     for(int i=rt;i!=fa[x][0];i=fa[i][0]) tmpl[++l]=i;
 78     pct=0;
 79     for(int i=egh[rt];i;i=eg[i].ne) getson(eg[i].b);
 80     sort(tmpr+1,tmpr+pct+1,cmp);
 81 
 82     int sh=0;
 83     for(int i=1,j=1;i<=pct&&ldep[tmpr[i]]!=-1;i++){
 84         for(;j<=l&&dep[tmpl[j]]>=ldep[tmpr[i]];j++){
 85             while(sh>1&&getk(stk[sh],stk[sh-1])<=getk(stk[sh],tmpl[j])) --sh;
 86             stk[++sh]=tmpl[j];
 87         }
 88         if(sh){
 89             int k=stk[1];
 90             if(sh!=1){
 91                 int a=1,b=sh-1;
 92                 while(a<=b){
 93                     int m=(a+b)>>1;
 94                     if(getk(stk[m],stk[m+1])<=p[tmpr[i]]) k=stk[m],b=m-1;
 95                     else k=stk[m+1],a=m+1;
 96                 }
 97             }
 98             dp[tmpr[i]]=min(dp[tmpr[i]],dp[k]+(dis[tmpr[i]]-dis[k])*p[tmpr[i]]+q[tmpr[i]]);
 99         }
100     }
101     for(int i=egh[rt];i;i=eg[i].ne){
102         cdq(eg[i].b,siz[eg[i].b]);
103     }
104 }
105 
106 inline void adeg(int a,int b,int l){
107     eg[++ect].b=b;eg[ect].l=l;eg[ect].ne=egh[a];egh[a]=ect;
108 }
109 
110 int main(){
111     int i,j,k;
112     N=rd();rd();
113     for(i=2;i<=N;i++){
114         int a=rd(),b=rd();p[i]=rd(),q[i]=rd(),l[i]=rd();
115         adeg(a,i,b);fa[i][0]=a;
116     }ldep[0]=-1;dep[1]=1;dfs1(1);
117     memset(dp,127,sizeof(dp));dp[1]=0;
118     cdq(1,N);    
119     for(i=2;i<=N;i++) printf("%lld
",dp[i]);
120     return 0;
121 }

 

以上是关于bzoj3672/luogu2305 购票 (运用点分治思想的树上cdq分治+斜率优化dp)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3672购票

BZOJ-3672购票 树分治 + 斜率优化DP

●BZOJ 3672 [Noi2014]购票

BZOJ3672[Noi2014]购票 树分治+斜率优化

bzoj3672: [Noi2014]购票

bzoj3672 [Noi2014]购票