• JZOJ 6754. 2020.07.18【NOI2020】模拟T3 (树链剖分+分治+闵科夫斯基和)


    题目大意:

    给一棵(n)个点的树,选(k=1 sim n)条不相交边,使得权值和最大。

    (n le 2 imes 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("
    ")
    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
    ", i, x, y);
    //	fo(u, 0, 1) fo(v, 0, 1) {
    //		pp("u = %d v = %d size = %d
    ", 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
    ", 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
    ", 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]);
    	}
    }
    
  • 相关阅读:
    iptables conntrack和state的区别
    shell中test命令方法详解
    Linux Shell 中各种括号的作用 ()、(())、[]、[[]]、{}
    mac terminal ssh连接linux乱码问题
    iptables 教程,iptables 详解,iptables 常见使用实例
    Redis实现主从复制(Master&Slave)
    TCP回射客户服务器模型(02 设置套接字选项、处理多并发)
    TCP回射客户服务器模型(01 socket bind listen accept connect)
    socket套接字(字节序、地址转换)
    TCP特点
  • 原文地址:https://www.cnblogs.com/coldchair/p/13357590.html
Copyright © 2020-2023  润新知