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\n",dp[i]);
120     return 0;
121 }

原文地址:https://www.cnblogs.com/Ressed/p/9696185.html

时间: 2025-01-13 03:39:06

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

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

3672: [Noi2014]购票 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1177  Solved: 562[Submit][Status][Discuss] Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的父亲用道路连接.为了方便起见,我们将全国的 n 个城市用 1 到 n 的整数编号.

[BZOJ 1492][NOI2007]货币兑换Cash(CDQ分治+斜率优化Dp)

Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的 价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法 .比例交易法分为两个方面:(a)卖出金券:顾客提

【uoj#244】[UER #7]短路 CDQ分治+斜率优化dp

题目描述 给出 $(2n+1)\times (2n+1)$ 个点,点 $(i,j)$ 的权值为 $a[max(|i-n-1|,|j-n-1|)]$ ,找一条从 $(1,1)$ 走到 $(2n+1,2n+1)$ 的路径,使得经过的点(包括起点和终点)权值和最小.求这个权值和. 输入 第一行一个正整数 $n$ . 第二行 $n+1$ 个正整数 $a[0],a[1],…,a[n]$ ,表示从内到外每层的中继器的延时值. 输出 输出一行一个数表示改造后的最短引爆时间. 样例输入 99 5 3 7 6 9

BZOJ 3963: [WF2011]MachineWorks [CDQ分治 斜率优化DP]

传送门 当然了WF的题uva hdu上也有 你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益.可以租借的机器有M台.每台机器有四个参数D,P,R,G.你可以在第D天花费P的费用(当然,前提是你有至少P元)租借这台机器,从第D+1天起,操作机器将为你产生每天G的收益.在你不再需要机器时,可以将机器卖掉,一次性获得R的收益.厂房里只能停留一台机器.不能在购买和卖出机器的那天操作机器,但是可以在同一天卖掉一台机器再买入一台.在第N+1天,你必须卖掉手上的机器

BZOJ 1492 NOI 2007 货币兑换Cash CDQ分治+斜率优化DP

题目大意:有两种金券,A和B.每一天有一个rate值,表示购入的比例:还有每一天AB金券的售价.现在给出初始的钱数,问最后能够获得多少钱. 思路:这算是神题了吧,啃论文啃别人代码将近一天才算有点明白. 首先题目中说的可以买一部分或者卖一部分是扯淡的,因为为了最大获利一定要全部买入,全部卖出.朴素的DP方程就好弄了. 设f[i]为第i天最多的B券的数量.那么f[i] = (rate[j] * f[j] * a[i] + f[j] * b[i]) / (rate[i] * a[i] + b[i])

bzoj1492[NOI2007]货币兑换Cash cdq分治+斜率优化dp

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5541  Solved: 2228[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金

bzoj2149拆迁队 斜率优化dp+分治

2149: 拆迁队 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 397  Solved: 177[Submit][Status][Discuss] Description lanxisi带领着他的拆迁队来整治一个街道.这个街道由N个旧房子组成,从左到右编号为1..N.每个旧房子i有一个正整数的美观度Ai. lanxisi希望整个街道从左到右美观度严格递增,也就是保证Ai<Aj(i<j).但是旧的街道明显不符合这个要求,于是lanxisi希望拆

【bzoj3672】购票

Portal -->bzoj3672 Solution 天知道我是怎么调完的qwq调到天昏地暗系列.. ? 不管这么多,先尝试列一个最简单的状态转移方程 用\(f[i]\)表示\(i\)点到\(1\)号点要花费的最少资金,\(dis[i]\)表示\(i\)到\(1\)号点的距离,那么有: \[ f[i]=min(f[j]+p[i]*(dis[i]-dis[j])+q[i]) \] 其中\(j\)是\(i\)的祖先且\(dis[i]-dis[j]<=l[i]\) ? 然后直接转移什么的肯定是不现

CDQ分治与整体二分总结

Cdq分治和整体二分是两个很奇妙的东西.他们都是通过离线的思想来进行优化,从而更快的求出解. 整体二分通俗的讲就是二分答案,但是它了不起的地方是一下子把所有的答案都二分出来了,从而可以一下子得出所有查询. CDQ分治通俗的讲就是二分查询.通常的做法是把所有的查询分成两半,然后通过递归先计算出左边一半的所有的查询,然后通过这些已知的左半边的值来更新右半边的值.这里,最最重要的思想是通过左半边来更新右半边.更具体一点,就是用左半边的修改来更新右半边的查询. 重要的事情说话三遍: CDQ分治就是通过左