BZOJ2870 最长道路

题意:给定树,有点权。求一条路径使得最小点权 * 总点数最大。只需输出这个最大值。5w。

解:树上路径问题,点分治。

考虑合并两个子树的时候,答案的形式是val1 * (d1 + d2),当1是新插入的节点的时候,只需在val比它大的点中选出一个最大的d2,这树状数组就可以做到。

当2是新插入的节点时候,好像需要凸包了?但是我们完全不虚啊,因为我们倒序枚举子树就能让2在1之前插入。

于是正反枚举两次子树,拿树状数组维护一下后缀最大值就行了。

复杂度O(nlog2n)

  1 /**
  2  * There is no end though there is a start in space. ---Infinity.
  3  * It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
  4  * Only the person who was wisdom can read the most foolish one from the history.
  5  * The fish that lives in the sea doesn't know the world in the land.
  6  * It also ruins and goes if they have wisdom.
  7  * It is funnier that man exceeds the speed of light than fish start living in the land.
  8  * It can be said that this is an final ultimatum from the god to the people who can fight.
  9  *
 10  * Steins;Gate
 11  */
 12 
 13 #include <bits/stdc++.h>
 14 
 15 #define forson(x, i) for(int i = e[x]; i; i = edge[i].nex)
 16 
 17 typedef long long LL;
 18 const int N = 50010, INF = 0x3f3f3f3f;
 19 
 20 struct Edge {
 21     int nex, v;
 22 }edge[N << 1], edge2[N << 1]; int tp, tp2;
 23 
 24 int e[N], n, siz[N], _n, root, small, e2[N], xx, d[N], Val[N];
 25 LL val[N], X[N], ans;
 26 bool del[N];
 27 
 28 inline void add(int x, int y) {
 29     tp++;
 30     edge[tp].v = y;
 31     edge[tp].nex = e[x];
 32     e[x] = tp;
 33     return;
 34 }
 35 
 36 inline void add2(int x, int y) {
 37     tp2++;
 38     edge2[tp2].v = y;
 39     edge2[tp2].nex = e2[x];
 40     e2[x] = tp2;
 41     return;
 42 }
 43 
 44 namespace ta {
 45     int ta[N];
 46     inline void add(int x, int v) {
 47         x = xx + 1 - x;
 48         for(int i = x; i <= xx; i += i & (-i)) {
 49             ta[i] = std::max(ta[i], v);
 50         }
 51         return;
 52     }
 53     inline void del(int x) {
 54         x = xx + 1 - x;
 55         for(int i = x; i <= xx; i += i & (-i)) {
 56             ta[i] = -INF;
 57         }
 58         return;
 59     }
 60     inline int getMax(int x) {
 61         x = xx + 1 - x;
 62         int ans = -INF;
 63         for(int i = x; i; i -= i & (-i)) {
 64             ans = std::max(ans, ta[i]);
 65         }
 66         return ans;
 67     }
 68 }
 69 
 70 void getroot(int x, int f) {
 71     siz[x] = 1;
 72     int large = 0;
 73     forson(x, i) {
 74         int y = edge[i].v;
 75         if(y == f || del[y]) continue;
 76         getroot(y, x);
 77         siz[x] += siz[y];
 78         if(siz[y] > large) {
 79             large = siz[y];
 80         }
 81     }
 82     if(_n - siz[x] > large) {
 83         large = _n - siz[x];
 84     }
 85     if(small > large) {
 86         small = large;
 87         root = x;
 88     }
 89     return;
 90 }
 91 
 92 void DFS_1(int x, int f) {
 93     siz[x] = 1;
 94     d[x] = d[f] + 1;
 95     Val[x] = std::min(Val[f], (int)val[x]);
 96     ans = std::max(ans, X[Val[x]] * (d[x] + ta::getMax(Val[x])));
 97     forson(x, i) {
 98         int y = edge[i].v;
 99         if(del[y] || y == f) continue;
100         DFS_1(y, x);
101         siz[x] += siz[y];
102     }
103     return;
104 }
105 
106 void DFS_2(int x, int f) {
107     ta::add(Val[x], d[x] + 1);
108     forson(x, i) {
109         int y = edge[i].v;
110         if(y == f || del[y]) continue;
111         DFS_2(y, x);
112     }
113     return;
114 }
115 
116 void DFS_3(int x, int f) {
117     ta::del(Val[x]);
118     forson(x, i) {
119         int y = edge[i].v;
120         if(del[y] || y == f) {
121             continue;
122         }
123         DFS_3(y, x);
124     }
125     return;
126 }
127 
128 void poi_div(int x) {
129     small = INF;
130     getroot(x, 0);
131     x = root;
132 
133     d[x] = 0;
134     Val[x] = val[x];
135     ta::add(Val[x], 1);
136     forson(x, i) {
137         int y = edge[i].v;
138         if(del[y]) continue;
139         DFS_1(y, x);
140         DFS_2(y, x);
141     }
142     DFS_3(x, 0);
143     // ---------
144     for(int i = e2[x]; i; i = edge2[i].nex) {
145         int y = edge2[i].v;
146         if(del[y]) continue;
147         DFS_1(y, x);
148         DFS_2(y, x);
149     }
150     ans = std::max(ans, X[val[x]] * ta::getMax(val[x]));
151     DFS_3(x, 0);
152 
153     del[x] = 1;
154     forson(x, i) {
155         int y = edge[i].v;
156         if(del[y]) continue;
157         _n = siz[y];
158         poi_div(y);
159     }
160     return;
161 }
162 
163 int main() {
164 
165     scanf("%d", &n);
166     for(int i = 1; i <= n; i++) {
167         scanf("%lld", &val[i]);
168         X[i] = val[i];
169     }
170     std::sort(X + 1, X + n + 1);
171     xx = std::unique(X + 1, X + n + 1) - X - 1;
172     for(int i = 1; i <= n; i++) {
173         val[i] = std::lower_bound(X + 1, X + xx + 1, val[i]) - X;
174     }
175     ans = X[xx];
176     for(int i = 1, x, y; i < n; i++) {
177         scanf("%d%d", &x, &y);
178         add(x, y); add(y, x);
179     }
180     for(int x = 1; x <= n; x++) {
181         forson(x, i) {
182             add2(x, edge[i].v);
183         }
184     }
185 
186     poi_div(1);
187 
188     printf("%lld\n", ans);
189     return 0;
190 }
AC代码

题外话:感觉能树形DP,但是要线段树合并 + 凸包合并,虚的一批...

还发现了一个O(nlogn)的做法,只需多叉转二叉然后O(n) - O(1)lca即可实现,瓶颈在于排序...

然而这题是边分治模板题...

posted @ 2019-04-14 19:01  huyufeifei  阅读(173)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

ReadEra 阅读书籍

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜