zoukankan      html  css  js  c++  java
  • 「gym


    description

    给定一棵带权树,对于 (kin[1, n - 1]) 的每个 (k),输出匹配数为 (k) 的最大权匹配的权和。

    problem link。

    solution

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

    不难想到 (f) 是凸的(根据费用流的性质),因此合并两个 (f) 的过程可以做到线性。

    如果在链上,可以分治做到 (O(nlog n))

    如果在树上,可以进行链分治:将树轻重链剖分,以重链为单位自底向上合并。具体来说你需要做两步:

    (1)对于每个点,合并它所有轻儿子的答案,可以分治;

    (2)对于每条重链,套用链的分治方法求出答案。

    总复杂度 (O(nlog^2n))

    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);
    	(*p) = (edge){v, w, adj[u]}, adj[u] = p;
    	(*q) = (edge){u, w, adj[v]}, adj[v] = q;
    }
    #define repG(p, x) for(edge *p=adj[x];p;p=p->nxt)
    
    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]);
    		}
    		h[1][1][l] = add(h[1][1][l], tp);
    	}
    	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]);
    		}
    		h[0][1][l] = add(h[0][1][l], tp0), h[1][1][l] = add(h[1][1][l], tp1);
    	}
    	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]);
    				vl b = merge(add(t0, t1), add(h[0][o2][m + 1], h[1][o2][m + 1]));
    				h[o1][o2][l] = add(move(a, t[m]), b);
    			}
    		}
    	}
    	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];
    		solve2(1, cnt), f[0][x] = add(h[0][0][1], h[0][1][1]), f[1][x] = add(h[1][0][1], h[1][1][1]), clear2(1);
    	}
    }
    
    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 ? '
    ' : ' ');
    	}
    }
    

    details

    合理使用 vector 可以简化代码难度。

    类似的题隔壁loj还有一道

  • 相关阅读:
    vim 的配置文件
    linux bash 的自动补全
    linux ping 命令
    linux 安装ifconfig
    dos exist 命令
    linux 用户的添加,组的添加,以及查看
    if else 的.bat 文件
    For 的.bat文件
    rmdir 的.bat文件
    dos set 命令
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/13412101.html
Copyright © 2011-2022 走看看