bzoj 3672 利用点分治将CDQ分治推广到树型结构上

最大的收获就是题目所说。

deal(s) : 处理节点s所在块的问题,并保证:

  1、s是该块中最靠近根节点的点,没有之一。

  2、s所在块到根节点的路径上的点全都用来更新过了s所在块的所有节点。

然后步骤是:

  1、找s所在块的重心c。

  2、如果s就是c,那么用c更新当前块的所有节点,然后“删除c”,递归处理新产生的子块。

  3、否则,删除c,deal(s),用c到s的路径(不包括c,包括s)更新c除了s子块的其他子块以及c,然后再用c去更新一次。

  4、递归处理其它子块。

  1 #include <cstdio>
  2 #include <cassert>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N 200010
  6 #define M N<<1
  7 #define fill(arr,lf,rg,v) memset(arr+lf,v,sizeof(arr[0])*(rg-lf+1))
  8 using namespace std;
  9
 10 typedef long long dnt;
 11 struct Vector {
 12     dnt x, y;
 13     Vector(){}
 14     Vector( dnt x, dnt y ):x(x),y(y){}
 15     Vector operator+( const Vector &o ) const { return Vector(x+o.x,y+o.y); }
 16     Vector operator-( const Vector &o ) const { return Vector(x-o.x,y-o.y); }
 17     double operator^( const Vector &o ) const { return (double)x*o.y-(double)y*o.x; }
 18 };
 19 typedef Vector Point;
 20 bool onleft( const Point &a, const Point &b, const Point &c ) {
 21     return ((b-a)^(c-a)) >= 0.0;
 22 }
 23 struct Convex {
 24     Point stk[N];
 25     int top;
 26     void init() {
 27         top=-1;
 28     }
 29     inline void append( const Point &p ) {
 30         while( top>0 && onleft(stk[top-1],stk[top],p) ) top--;
 31         stk[++top] = p;
 32     }
 33     const Point& query( dnt k ) {
 34         int lf=0;
 35         int rg=top;
 36         if( lf==rg ) return stk[top];
 37         assert(k*(stk[lf].x-stk[lf+1].x)>=0);
 38         if( k*(stk[lf].x-stk[lf+1].x) >= (stk[lf].y-stk[lf+1].y) )
 39             return stk[lf];
 40         assert(k*(stk[rg-1].x-stk[rg].x)>=0);
 41         if( k*(stk[rg-1].x-stk[rg].x) <= (stk[rg-1].y-stk[rg].y) )
 42             return stk[rg];
 43         lf++;
 44         rg--;
 45         while( lf<rg ) {
 46             int mid=(lf+rg)>>1;
 47             assert(k*(stk[mid].x-stk[mid+1].x)>=0);
 48             if( k*(stk[mid].x-stk[mid+1].x) > (stk[mid].y-stk[mid+1].y) )
 49                 rg=mid;
 50             else
 51                 lf=mid+1;
 52         }
 53         return stk[lf];
 54     }
 55 };
 56
 57 int n, case_type;
 58 int head[N], next[M], dest[M], etot;
 59 dnt wp[N], wq[N], lim[N], ws[M];
 60 int anc[N], fat[N], vis[N], siz[N], bac[N];
 61 dnt dep[N], dp[N];
 62 int qu[N], bg, ed;
 63 Convex convex;
 64
 65 void adde( int u, int v, dnt s ) {
 66     etot++;
 67     dest[etot] = v;
 68     next[etot] = head[u];
 69     ws[etot] = s;
 70     head[u] = etot;
 71 }
 72 void bfs( int s ) {
 73     qu[bg=ed=1] = s;
 74     anc[s] = 0;
 75     dep[s] = 0;
 76     while( bg<=ed ) {
 77         int u=qu[bg++];
 78         for( register int t=head[u]; t; t=next[t] ) {
 79             int v=dest[t];
 80             if( v==anc[u] ) continue;
 81             qu[++ed] = v;
 82             anc[v] = u;
 83             dep[v] = dep[u]+ws[t];
 84         }
 85     }
 86 }
 87 int getc( int s ) {
 88     qu[bg=ed=1] = s;
 89     fat[s] = 0;
 90     bac[s] = 0;
 91     siz[s] = 0;
 92     while( bg<=ed ) {
 93         int u=qu[bg++];
 94         for( register int t=head[u]; t; t=next[t] ) {
 95             int v=dest[t];
 96             if( vis[v] || v==fat[u] ) continue;
 97             qu[++ed] = v;
 98             fat[v] = u;
 99             bac[v] = 0;
100             siz[v] = 0;
101         }
102     }
103     int c = 0;
104     for( register int i=ed; i>=1; i-- ) {
105         int u=qu[i];
106         siz[u]++;
107         if( fat[u] ) {
108             int f=fat[u];
109             siz[f]+=siz[u];
110             if( siz[u]>bac[f] ) bac[f]=siz[u];
111         }
112     }
113     for( register int i=1; i<=ed; i++ ) {
114         int u=qu[i];
115         if( bac[u]<siz[s]-siz[u] ) bac[u]=siz[s]-siz[u];
116         if( !c || bac[u]<bac[c] ) c=u;
117     }
118     //fprintf( stderr, "%d\n", c );
119     return c;
120 }
121 void flood( int s ) {
122     qu[bg=ed=1] = s;
123     fat[s] = 0;
124     while( bg<=ed ) {
125         int u=qu[bg++];
126         for( register int t=head[u]; t; t=next[t] ) {
127             int v=dest[t];
128             if( vis[v] || v==fat[u] ) continue;
129             qu[++ed] = v;
130             fat[v] = u;
131         }
132     }
133 }
134 inline void update( const Point &p, int u ) {
135     dnt v = p.y + wp[u]*(dep[u]-p.x) + wq[u];
136     if( dp[u]>v ) dp[u]=v;
137 }
138 bool cmp( int a, int b ) {
139     return dep[a]-lim[a]>dep[b]-lim[b];
140 }
141 void vdcp( int s ) {
142     int c=getc(s);
143     vis[c] = true;
144     if( c==s ) {
145         Point pc = Point(dep[c],dp[c]);
146         flood(s);
147         for( int i=1; i<=ed; i++ ) {
148             int u=qu[i];
149             if( u!=s && dep[u]-lim[u]<=pc.x ) update(pc,u);
150         }
151     } else {
152         vdcp(s);
153         flood(c);
154         sort( qu+1, qu+1+ed, cmp );
155         convex.init();
156         int cur = c;
157         for( register int i=1; i<=ed; i++ ) {
158             int u=qu[i];
159             while( cur!=s && dep[anc[cur]]>=dep[u]-lim[u] ) {
160                 cur=anc[cur];
161                 convex.append( Point(dep[cur],dp[cur]) );
162             }
163             if( convex.top>=0 )
164                 update( convex.query(wp[u]), u );
165         }
166         Point cp = Point(dep[c],dp[c]);
167         for( register int i=ed; i>=1; i-- ) {
168             int u=qu[i];
169             if( u==c ) continue;
170             if( dep[u]-lim[u]>dep[c] ) break;
171             update( cp, u );
172         }
173     }
174     for( int t=head[c]; t; t=next[t] ) {
175         int v=dest[t];
176         if( vis[v] ) continue;
177         vdcp(v);
178     }
179 }
180 int main() {
181     scanf( "%d%d", &n, &case_type );
182     for( int i=2; i<=n; i++ ) {
183         int f;
184         dnt s;
185         scanf( "%d%lld%lld%lld%lld", &f, &s, wp+i, wq+i, lim+i );
186         adde( f, i, s );
187         adde( i, f, s );
188     }
189     fill( dp, 0, n, 0x3f );
190     dp[1] = 0;
191     bfs(1);
192     vdcp(1);
193     for( int i=2; i<=n; i++ )
194         printf( "%lld\n", dp[i] );
195 }

时间: 2024-10-19 10:11:20

bzoj 3672 利用点分治将CDQ分治推广到树型结构上的相关文章

COGS 2479. [HZOI 2016]偏序 [CDQ分治套CDQ分治 四维偏序]

传送门 给定一个有n个元素的序列,元素编号为1~n,每个元素有三个属性a,b,c,求序列中满足i<j且ai<aj且bi<bj且ci<cj的数对(i,j)的个数. 对于100%的数据,1<=n<=50000,保证所有的ai.bi.ci分别组成三个1~n的排列. $CDQ$分治套$CDQ$分治也不是很难嘛 对于本题,设四维$a,b,c,d$ $Sort\ at\ a$ $CDQ(l,r)$ $\quad CDQ(l,mid)$ $\quad CDQ(mid+1,r)$ $\

【BZOJ】1176: [Balkan2007]Mokia(cdq分治)

http://www.lydsy.com/JudgeOnline/problem.php?id=1176 在写这题的时候思维非常逗啊........2333................... 最后不得不去看别人的代码.. 噗,,我怎么没想到二维前缀和.................... orz zyf 那么对于一个矩形,我们拆成四个点,那么就可以和add操作一起cdq分治! orz cdq分治的话很好想的: 定义$solve(l, r)$表示用l~mid来更新mid+1~r. 考虑如何$

BZOJ 2726: [SDOI2012]任务安排( dp + cdq分治 )

考虑每批任务对后面任务都有贡献, dp(i) = min( dp(j) + F(i) * (T(i) - T(j) + S) ) (i < j <= N)  F, T均为后缀和. 与j有关的量只有t = dp(j) - F(i) * T(j) , 我们要最小化它. dp(j)->y, T(j)->x, 那么y = F(i) * x + t, 就是给一些点和一个斜率...然后最小化截距, 显然维护下凸包就可以了. 然后因为无比坑爹的出题人....时间可以为负数, 所以要用平衡树维护(

BZOJ 2716: [Violet 3]天使玩偶 [CDQ分治]

传送门 题意: 维护二维点集P,支持以下两个操作(1)插入点(x,y)(2)给定询问(x,y),求点集中离询问点最近的点距离定义为曼哈顿距离Dis(P1,P2)=|x1-x2|+|y1-y2|n,m<=500000x,y<=1000000 时间,$x$,$y$ $CDQ$分治里需要四个象限分类讨论,树状数组维护最大值 然后有两个象限是后缀和 然后跟$PoPoQQQ$学了一个神奇的技巧,树状数组加一个时间戳,就可以不用每次清空之前的操作了 #include <iostream> #i

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

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

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])

【cdq分治】cdq分治与整体二分学习笔记Part1.整体二分

之所以把cdq分治和整体二分放在一起学习,是因为他们两个实在太像了-不管是做法还是代码- 感觉整体二分可能会比cdq分治稍微简单那么一点点?所以先学整体二分.(感觉他们的区别在于整体二分是对每个操作二分答案,cdq是分治了操作序列) 整体二分是对答案进行二分,其具体操作如下: (比如以ZJOJ2013K大数查询为例) 具体过程 Step1.从(L,R)二分答案.mid=(L+R)>>1,用线段树维护原序列中(a,b)位置比mid大的数有多少个,同时记录对序列的操作分别是什么操作. Step2.

【BZOJ 4170】 4170: 极光 (CDQ分治)

4170: 极光 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 121  Solved: 64 Description "若是万一琪露诺(俗称rhl)进行攻击,什么都好,冷静地回答她的问题来吸引她.对方表现出兴趣的话,那就慢 慢地反问.在她考虑答案的时候,趁机逃吧.就算是很简单的问题,她一定也答不上来." --<上古之魔书> 天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列a[i],远古之魔书上记载到:2个

BZOJ 2244: [SDOI2011]拦截导弹 DP+CDQ分治

2244: [SDOI2011]拦截导弹 Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小.也就是拦截导弹的数量最多的方案.但是