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]);
	}
}
posted @ 2020-07-21 21:37  Cold_Chair  阅读(293)  评论(0编辑  收藏  举报