JZOJ 6754. 2020.07.18【NOI2020】模拟T3 (树链剖分+分治+闵科夫斯基和)
题目大意:
给一棵\(n\)个点的树,选\(k=1 \sim n\)条不相交边,使得权值和最大。
\(n \le 2 \times 10^5\)
题解:
考虑设\(f[i][j][0/1]\)表示\(i\)子树里选了\(j\)条边,\(i\)选了没有的最大值。
猜性质,它是凸的。
那么就可以闵科夫斯基和快速合并两个这样的数组。
于是可以套上树链剖分:
1.每个点先把轻儿子合并
2.一条重链再合并
时间复杂度:\(O(n ~ log^2 n)\)
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
int tp, n, L, R;
const int N = 2e5 + 5;
int fi[N], to[N * 2], nt[N * 2], w[N * 2], tot = 1;
void link(int x, int y, int z) {
nt[++ tot] = fi[x], to[tot] = y, w[tot] = z, fi[x] = tot;
}
int x, y, z;
int siz[N], son[N], fa[N], fv[N];
void dg(int x) {
siz[x] = 1;
for(int i = fi[x]; i; i = nt[i]) {
int y = to[i]; if(y == fa[x]) continue;
fa[y] = x;
fv[y] = w[i];
dg(y);
siz[x] += siz[y];
if(siz[y] > siz[son[x]]) son[x] = y;
}
}
#define V vector<ll>
#define pb push_back
#define si size()
#define re resize
V mer(V a, V b) {
if(a.empty()) return a;
if(b.empty()) return b;
int n = a.si - 1, m = b.si - 1;
V c; c.re(n + m + 1);
fd(i, n, 1) a[i] -= a[i - 1];
fd(i, m, 1) b[i] -= b[i - 1];
ll s = a[0] + b[0]; int x = 0;
c[0] = s;
int l = 1, r = 1;
while(l <= n && r <= m) {
if(a[l] >= b[r]) s += a[l ++]; else s += b[r ++];
c[++ x] = s;
}
while(l <= n) s += a[l ++], c[++ x] = s;
while(r <= m) s += b[r ++], c[++ x] = s;
return c;
}
const ll inf = 1e18;
V max(V a, V b) {
while(a.si < b.si) a.pb(-inf);
ff(i, 0, b.si) a[i] = max(a[i], b[i]);
return a;
}
V jia(V a, ll v) {
if(a.empty()) return a;
a.push_back(0);
fd(i, a.si - 1, 1) a[i] = a[i - 1] + v;
a[0] = -inf;
return a;
}
int d[N], d0;
#define pvv pair<V, V>
#define fs first
#define se second
pvv f[N];
pvv fz(int x, int y) {
if(x > y) {
V a; a.clear(); a.pb(0);
return pvv(a, a);
}
if(x == y) {
return pvv(max(f[d[x]].fs, f[d[x]].se), jia(f[d[x]].fs, fv[d[x]]));
}
int m = x + y >> 1;
pvv a = fz(x, m), b = fz(m + 1, y);
pvv c; c.fs = mer(a.fs, b.fs);
c.se = max(mer(a.fs, b.se), mer(a.se, b.fs));
return c;
}
#define i0 i + i
#define i1 i + i + 1
V t[N * 4][2][2];
void gg(int i, int x, int y) {
if(x == y) {
V a; a.clear();
t[i][0][1] = t[i][1][0] = a;
t[i][0][0] = f[d[x]].fs;
t[i][1][1] = f[d[x]].se;
return;
}
int m = x + y >> 1;
gg(i0, x, m); gg(i1, m + 1, y);
fo(u, 0, 1) fo(v, 0, 1) t[i][u][v].clear();
fo(u, 0, 1) fo(v, 0, 1) {
V a = jia(mer(t[i0][u][0], t[i1][0][v]), fv[d[m + 1]]);
int nu = u, nv = v;
if(x == m) nu = 1;
if(m + 1 == y) nv = 1;
t[i][nu][nv] = max(t[i][nu][nv], a);
a = mer(max(t[i0][u][0], t[i0][u][1]), max(t[i1][0][v], t[i1][1][v]));
t[i][u][v] = max(t[i][u][v], a);
}
// pp("i = %d x = %d y = %d\n", i, x, y);
// fo(u, 0, 1) fo(v, 0, 1) {
// pp("u = %d v = %d size = %d\n", u, v, t[i][u][v].si);
// }
}
void du(int x) {
for(int i = fi[x]; i; i = nt[i]) {
int y = to[i]; if(y == fa[x]) continue;
du(y);
}
d0 = 0;
for(int i = fi[x]; i; i = nt[i]) {
int y = to[i]; if(y == fa[x] || y == son[x]) continue;
d[++ d0] = y;
}
f[x] = fz(1, d0);
if(son[fa[x]] != x) {
d0 = 0;
for(int p = x; p; p = son[p])
d[++ d0] = p;
// pp("x = %d d0 = %d\n", x, d0);
gg(1, 1, d0);
f[x] = pvv(max(t[1][0][0], t[1][0][1]), max(t[1][1][0], t[1][1][1]));
}
// pp("x = %d %d %d\n", x, f[x].fs.si, f[x].se.si);
}
ll ans[N];
int main() {
freopen("accompany.in", "r", stdin);
freopen("accompany.out", "w", stdout);
scanf("%d %d %d %d", &tp, &n, &L, &R);
fo(i, 1, n - 1) {
scanf("%d %d %d", &x, &y, &z);
link(x, y, z); link(y, x, z);
}
dg(1);
// fo(i ,1, n) pp("%d ", son[i]); hh;
du(1);
fo(i, 1, n) ans[i] = -inf;
V a = max(f[1].fs, f[1].se);
ff(i, 1, a.si) ans[i] = a[i];
fo(i, L, R) {
if(ans[i] == -inf) pp("- "); else
pp("%lld ", ans[i]);
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址