ZOJ--3937(点分治,斜率优化)

2016-04-27 02:00:42

传送门

题意:给出一棵带点权的树,点编号1~N,要求选一段路径,且仅能从标号大的点走到标号小的点,设路径为 p1->p2->p3 ....->pk,令 f = Sigma( i * weight of pi ) , 1<=i<=k,要求最大的 f

思路:考虑点分治,对于每个分治中心,将答案路径拆分为一条从中心向下标号递减 和 一条标号递增的路径。

  对于当前一个子树,找出重心后,DFS一遍可以找出一条唯一的从重心向下的标号递减的路径,设路径为 W1

  0:设 dep[i] 为 i 点的深度

  1:对于 W1 上的结点 a1 , a2 , a3 ... 我们设 A[i] = Sigma( (i + 1 - j) * weight of aj ) , 1<=j<=i,其含义就是如果从重心走到 i 得到的 f 值

  2:然后我们需要找到从重心向下标号递增的路径 W2,此时路径是不唯一的,对于 W2 上的结点 a1 , a2 , a3 ... 我们设 S[i] = Sigma( weight of aj ) , A[i] = Sigma( j * weight of aj ) , 1<=j<=i

  假设我们取 W2 上的 i 点,以及 W1上的 j 点构成答案,那么 f = A[i] + ( dep[j] - 1) * S[i] + A[j]

  3:将上式转化为:A[j] = -S[i] * ( dep[j] - 1) - A[i] + f

  4:于是我们可以维护一个关于点集(dep[j] , A[j])的凸壳

  5:因此我们只要再DFS一遍,沿着标号递增的路径,对于每个点 i 在凸壳中三分查找对于 i 的最优节点 j,更新答案

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <time.h>
  5 #include <math.h>
  6 #include <vector>
  7 #include <iostream>
  8 #include <algorithm>
  9 using namespace std;
 10 
 11 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
 12 #define MP(a,b) make_pair(a,b)
 13 #define PB push_back
 14 #define X first
 15 #define Y second
 16 
 17 typedef long long ll;
 18 typedef pair<ll,ll> pll;
 19 const int inf = (1 << 30) - 1;
 20 const ll  INF = 1LL << 60;
 21 const int MAXN = 200010;
 22 
 23 int T,N,B[MAXN],sz[MAXN],szmin,top,pcnt;
 24 bool vis[MAXN];
 25 vector<int> G[MAXN];
 26 ll ans,A[MAXN],S[MAXN];
 27 pll sta[MAXN],P[MAXN];
 28 
 29 inline void Init(){
 30     for(int i = 1; i <= N; ++i) G[i].clear();
 31     memset(vis,false,sizeof(vis));
 32 }
 33 
 34 void Dfs_init(int p,int total,int pre,int &root){
 35     sz[p] = 1;
 36     int tmax = -inf;
 37     for(int i = 0; i < G[p].size(); ++i){
 38         int v = G[p][i];
 39         if(v == pre || vis[v]) continue;
 40         Dfs_init(v,total,p,root);
 41         sz[p] += sz[v];
 42         tmax = max(tmax,sz[v]);
 43     }
 44     tmax = max(tmax,total - sz[p]);
 45     if(tmax < szmin){
 46         szmin = tmax;
 47         root = p;
 48     }
 49 }
 50 
 51 void Dfs_dep(int p,int d){
 52     P[++pcnt] = MP(d - 1,A[p]);
 53     ans = max(ans,A[p]);
 54     for(int i = 0; i < G[p].size(); ++i){
 55         int v = G[p][i];
 56         if(vis[v] || v > p) continue;
 57         S[v] = S[p] + B[v];
 58         A[v] = A[p] + S[v];
 59         Dfs_dep(v,d + 1);
 60         return;
 61     }
 62 }
 63 
 64 void Build(){
 65     top = 0;
 66     sta[++top] = P[1];
 67     for(int i = 2; i <= pcnt; ++i){
 68         while(top >= 2){
 69             ll cur = (P[i].Y - sta[top].Y) * (sta[top].X - sta[top - 1].X)
 70                 - (sta[top].Y - sta[top - 1].Y) * (P[i].X - sta[top].X);
 71             if(cur >= 0) --top;
 72             else break;
 73         }
 74         sta[++top] = P[i];
 75     }
 76 }
 77 
 78 ll Cal(int p,ll k){
 79     return k * sta[p].X + sta[p].Y;
 80 }
 81 
 82 ll Solve(ll k){
 83     int l = 1,r = top;
 84     while(l < r - 1){
 85         int mid1 = getmid(l,r);
 86         int mid2 = getmid(mid1,r);
 87         if(mid1 == mid2) break;
 88         ll res1 = Cal(mid1,k),res2 = Cal(mid2,k);
 89         if(res1 > res2) r = mid2;
 90         else l = mid1;
 91     }
 92     ll res = -INF;
 93     for(int i = l; i <= r; ++i) res = max(res,Cal(i,k));
 94     return res;
 95 }
 96 
 97 void Dfs_res(int p,int d,int &root){
 98     ans = max(ans,A[p] + B[root]);
 99     ans = max(ans,Solve(S[p]) + A[p]);
100     for(int i = 0; i < G[p].size(); ++i){
101         int v = G[p][i];
102         if(vis[v] || v < p) continue;
103         S[v] = S[p] + B[v];
104         A[v] = A[p] + 1ll * (d + 1) * B[v];
105         Dfs_res(v,d + 1,root);
106     }
107 }
108 
109 void TreeDAC(int p,int total){
110     int root;
111     szmin = N;
112     pcnt = 0;
113     Dfs_init(p,total,-1,root);
114     A[root] = S[root] = B[root];
115     Dfs_dep(root,1);
116     Build();
117     A[root] = S[root] = 0;
118     Dfs_res(root,1,root);
119     vis[root] = true;
120     for(int i = 0; i < G[root].size(); ++i){
121         int v = G[root][i];
122         if(vis[v]) continue;
123         TreeDAC(v,sz[v]);
124     }
125 }
126 
127 int main(){
128     scanf("%d",&T);
129     while(T--){
130         scanf("%d",&N);
131         Init();
132         for(int i = 1; i <= N; ++i) scanf("%d",&B[i]);
133         for(int i = 2; i <= N; ++i){
134             int a;
135             scanf("%d",&a);
136             G[i].PB(a);
137             G[a].PB(i);
138         }
139         ans = 0;
140         TreeDAC(1,N);
141         printf("%lld\n",ans);
142     }
143     return 0;
144 }

 

posted @ 2016-04-27 02:19  Naturain  阅读(534)  评论(0编辑  收藏  举报