• UOJ462 新年的小黄鸭【线段树,dp】


    给定 (n) 个点的树,要求一种树剖方案使得"代价"尽可能小。

    (nle 10^5)


    (f_u) 表示只考虑 (u) 的子树时的代价,枚举重链 ((u,v)),其中 (v) 是叶子。

    代价有两部分,一部分是重链连出的子树的 (f+siz) 之和,还有一部分是重链的代价:设重链是 (u=a_0,cdots,a_d=v),则为 (siz_{a_1}+sum_{ige 0}siz_{a_{2^i+1}})。预处理出每个点的 (1)(2^i+1) 级儿子,就可以那贡献在自底而上的 dp 过程中处理成 dfs 序区间加。

    按叶子 dfs 序建线段树,维护区间加、区间求 (min),时间复杂度 (O(nlog^2n)),空间 (O(nlog n))

    #include<bits/stdc++.h>
    #define PB emplace_back
    using namespace std;
    const int N = 100003, M = 1<<18;
    template<typename T>
    void rd(T &x){
    	int ch = getchar(); x = 0;
    	for(;ch < '0' || ch > '9';ch = getchar());
    	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
    }
    int n, dfn[N], out[N], siz[N], tim, fa[17][N], seg[M], tag[M], dp[N];
    vector<int> son[N], G[N];
    void ptag(int x, int v){seg[x] += v; tag[x] += v;}
    void pdown(int x){
    	if(tag[x]){
    		ptag(x<<1, tag[x]);
    		ptag(x<<1|1, tag[x]);
    		tag[x] = 0;
    		return;
    	}
    }
    void upd(int l, int r, int v, int x = 1, int L = 1, int R = tim){
    	if(l <= L && R <= r){ptag(x, v); return;}
    	int md = L+R>>1; pdown(x);
    	if(l <= md) upd(l, r, v, x<<1, L, md);
    	if(md < r) upd(l, r, v, x<<1|1, md+1, R);
    	seg[x] = min(seg[x<<1], seg[x<<1|1]);
    }
    int qry(int l, int r, int x = 1, int L = 1, int R = tim){
    	if(l <= L && R <= r) return seg[x];
    	int md = L+R>>1; pdown(x);
    	if(r <= md) return qry(l, r, x<<1, L, md);
    	if(md < l) return qry(l, r, x<<1|1, md+1, R);
    	return min(qry(l, r, x<<1, L, md), qry(l, r, x<<1|1, md+1, R));
    }
    void dfs1(int x){
    	siz[x] = 1;
    	for(int i = 0;i < 16;++ i)
    		fa[i+1][x] = fa[i][fa[i][x]];
    	if(x > 1) son[fa[0][x]].PB(x);
    	for(int i = 0, v;i < 17;++ i)
    		if(v = fa[0][fa[i][x]]) son[v].PB(x);
    	dfn[x] = tim+1;
    	if(x > 1 && G[x].size() == 1) ++tim;
    	for(int v : G[x]) if(v != fa[0][x]){
    		fa[0][v] = x; dfs1(v); siz[x] += siz[v];
    	} out[x] = tim;
    }
    void dfs2(int x){
    	int sum = 0;
    	for(int v : G[x]) if(v != fa[0][x]){
    		dfs2(v); sum += siz[v] + dp[v];
    	}
    	for(int v : G[x]) if(v != fa[0][x])
    		upd(dfn[v], out[v], sum-siz[v]-dp[v]);
    	for(int v : son[x]) upd(dfn[v], out[v], siz[v]);
    	dp[x] = qry(dfn[x], out[x]);
    	for(int v : son[x]) upd(dfn[v], out[v], -siz[v]);
    }
    int main(){
    	rd(n);
    	for(int i = 1, u, v;i < n;++ i){
    		rd(u); rd(v);
    		G[u].PB(v); G[v].PB(u); 
    	} dfs1(1); dfs2(1);
    	printf("%d
    ", dp[1]);
    }
    
  • 相关阅读:
    razor 拼接字符串
    转,CV和resume的区别
    b/s开发者的困境
    sql 下,float和numeric
    VS2010 + Entity FrameWork 4.4 +Mvc 4.0 出现的错误
    Nuget 管理entity framework
    关于 Code First
    C# 输出控制台结果到文件
    WCF wsdlexception(at/html):faultCode=INVALID_WSDL
    Silverlight环境配置
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/14932474.html
Copyright © 2020-2023  润新知