# 「gym - 102331J」Jiry Matchings

## solution

$f_{0/1,x,i}$ 表示在 $x$ 的子树中选 $i$ 条匹配，不选中/选中 $x$ 的最大和。

（1）对于每个点，合并它所有轻儿子的答案，可以分治；

（2）对于每条重链，套用链的分治方法求出答案。

## code

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef vector<ll> vl;

const int N = 200000;
const ll INF = (1ll << 60);

struct edge{
int to, dis; edge *nxt;
}edges[2*N + 5], *adj[N + 5], *ecnt = edges;
void adde(int u, int v, int w) {
edge *p = (++ecnt), *q = (++ecnt);
}

int fa[N + 5], siz[N + 5], hvy[N + 5], hd[N + 5];
void dfs(int x, int f) {
siz[x] = 1, hvy[x] = 0, fa[x] = f;
repG(p, x) if( p->to != f ) {
dfs(p->to, x), siz[x] += siz[p->to];
if( siz[hvy[x]] < siz[p->to] )
hvy[x] = p->to, hd[x] = p->dis;
}
}

vl merge(const vl &a, const vl &b) {
if( a.empty() ) return b;
if( b.empty() ) return a;

int na = a.size(), nb = b.size(); vl c(na + nb - 1, -INF);

int pa = 1, pb = 1, pc = 1; c[0] = a[0] + b[0];
while( pa < na && pb < nb ) {
if( a[pa] - a[pa - 1] > b[pb] - b[pb - 1] )
c[pc] = c[pc - 1] + a[pa] - a[pa - 1], pa++, pc++;
else  c[pc] = c[pc - 1] + b[pb] - b[pb - 1], pb++, pc++;
}
while( pa < na ) c[pc] = c[pc - 1] + a[pa] - a[pa - 1], pa++, pc++;
while( pb < nb ) c[pc] = c[pc - 1] + b[pb] - b[pb - 1], pb++, pc++;

return c;
}
vl add(const vl &a, const vl &b) {
int na = a.size(), nb = b.size(); vl c(max(na, nb), -INF);
for(int i=0;i<na;i++) c[i] = max(c[i], a[i]);
for(int i=0;i<nb;i++) c[i] = max(c[i], b[i]);
return c;
}
vl move(const vl &a, const int &d) {
int na = a.size(); vl c(na + 1, -INF);
for(int i=0;i<na;i++) c[i + 1] = max(c[i + 1], a[i] + d);
return c;
}

vl f[2][N + 5], g[2][N + 5], h[2][2][N + 5]; int t[N + 5], cnt;

void get1(vl &v0, vl &v1, int d) {
cnt++, g[0][cnt] = add(v0, v1), g[1][cnt] = move(v0, d);
v0.clear(), v1.clear();
}
void clear1(int x) {
g[0][x].clear(), g[1][x].clear();
}
void solve1(int l, int r) {
if( l == r ) return ;

int m = (l + r) >> 1;
solve1(l, m), solve1(m + 1, r);

vl a = merge(g[0][l], g[0][m + 1]);
vl b = merge(g[0][l], g[1][m + 1]);
vl c = merge(g[1][l], g[0][m + 1]);
g[0][l] = a, g[1][l] = add(b, c), clear1(m + 1);
}

void get2(vl &v0, vl &v1) {
cnt++, h[0][1][cnt].clear(), h[1][0][cnt].clear(), h[0][0][cnt] = v0, h[1][1][cnt] = v1;
v0.clear(), v1.clear();
}
void clear2(int x) {
h[0][0][x].clear(), h[0][1][x].clear(), h[1][0][x].clear(), h[1][1][x].clear();
}
void solve2(int l, int r) {
if( l == r ) return ;

int m = (l + r) >> 1;
solve2(l, m), solve2(m + 1, r);

if( l + 1 == r ) {
vl tp = move(merge(h[0][0][l], h[0][0][m + 1]), t[m]);
for(int o1=0;o1<=1;o1++) {
vl to1 = h[o1][o1][l];
for(int o2=0;o2<=1;o2++)
h[o1][o2][l] = merge(to1, h[o2][o2][m + 1]);
}
}
else if( l + 2 == r ) {
vl tp0 = move(merge(h[0][0][l], h[0][0][m + 1]), t[m]);
vl tp1 = move(merge(h[1][0][l], h[0][0][m + 1]), t[m]);
for(int o1=0;o1<=1;o1++) {
vl t0 = h[o1][0][l], t1 = h[o1][1][l];
for(int o2=0;o2<=1;o2++)
h[o1][o2][l] = merge(add(t0, t1), h[o2][o2][m + 1]);
}
}
else {
for(int o1=0;o1<=1;o1++) {
vl t0 = h[o1][0][l], t1 = h[o1][1][l];
for(int o2=0;o2<=1;o2++) {
vl a = merge(t0, h[0][o2][m + 1]);
}
}
}
clear2(m + 1);
}

void dfs2(int x, int tp) {
if( !hvy[x] )
f[0][x] = vl(1, 0), f[1][x] = vl(1, 0);
else {
repG(p, x) if( p->to != fa[x] && p->to != hvy[x] )
dfs2(p->to, p->to);

dfs2(hvy[x], tp), cnt = 0;
repG(p, x) if( p->to != fa[x] && p->to != hvy[x] )
get1(f[0][p->to], f[1][p->to], p->dis);
if( cnt == 0 ) f[0][x] = vl(1, 0), f[1][x] = vl(1, 0);
else solve1(1, cnt), f[0][x] = g[0][1], f[1][x] = g[1][1], clear1(1);
}

if( x == tp ) {
cnt = 0; for(int i=x;i;i=hvy[i]) get2(f[0][i], f[1][i]), t[cnt] = hd[i];
}
}

int main() {
//	freopen("data.in", "r", stdin);

int n; scanf("%d", &n);
for(int i=1,u,v,w;i<n;i++)
scanf("%d%d%d", &u, &v, &w), adde(u, v, w);
dfs(1, 0), dfs2(1, 1);

vl v = add(f[0][1], f[1][1]); f[0][1].clear(), f[1][1].clear();
for(int i=1;i<n;i++) {
if( i < (int)v.size() ) printf("%lld", v[i]);
else putchar('?');

putchar(i + 1 == n ? '\n' : ' ');
}
}


## details

posted @ 2020-07-31 20:53  Tiw_Air_OAO  阅读(99)  评论(0编辑  收藏