• dsu on tree(CF600E Lomsat gelral)


    题意

    一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。

    dsu on tree

    用来解决子树问题
    好像不能带修改??

    暴力做这个题,就是每次扫一遍子树统计答案
    时间(O(n^2))

    或者会高级的数据结构解决
    空间,编程难度是个挑战

    然而(dsu on tree)树上启发式合并则是一个好方法
    它通过增加对重儿子子树信息的利用来提高效率

    流程:

    递归轻儿子
    递归重儿子
    统计答案
    如果该点为它父亲的重儿子,保存信息
    否则删除信息

    复杂度分析:
    每个点被扫到的次数只有它到根的路径上轻边的次数*(2)
    也就是(log)
    那么总复杂度为空间(O(n)),时间(O(nlogn))

    该题代码

    # include <bits/stdc++.h>
    # define IL inline
    # define RG register
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    
    IL int Input(){
    	RG int x = 0, z = 1; RG char c = getchar();
    	for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    	for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    	return x * z;
    }
    
    const int maxn(1e5 + 5);
    
    int n, first[maxn], cnt, col[maxn], size[maxn], son[maxn], vis[maxn], num[maxn], mx;
    ll sum[maxn], ans[maxn];
    
    struct Edge{
    	int to, next;
    } edge[maxn << 1];
    
    IL void Add(RG int u, RG int v){
    	edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;
    }
    
    IL void Dfs(RG int u, RG int ff){
    	size[u] = 1;
    	for(RG int e = first[u]; e != -1; e = edge[e].next){
    		RG int v = edge[e].to;
    		if(v != ff){
    			Dfs(v, u);
    			size[u] += size[v];
    			if(size[v] > size[son[u]]) son[u] = v;
    		}
    	}
    }
    
    IL void Update(RG int u, RG int ff, RG int val){
    	sum[num[col[u]]] -= col[u];
    	num[col[u]] += val;
    	sum[num[col[u]]] += col[u];
    	if(val > 0) mx = max(mx, num[col[u]]);
    	else while(mx && !sum[mx]) --mx;
    	for(RG int e = first[u]; e != -1; e = edge[e].next)
    		if(edge[e].to != ff && !vis[edge[e].to]) Update(edge[e].to, u, val);
    }
    
    IL void Solve(RG int u, RG int ff, RG int op){
    	size[u] = 1;
    	for(RG int e = first[u]; e != -1; e = edge[e].next)
    		if(edge[e].to != ff && edge[e].to != son[u]) Solve(edge[e].to, u, 0);
    	if(son[u]) Solve(son[u], u, 1), vis[son[u]] = 1;
    	Update(u, ff, 1), vis[son[u]] = 0;
    	ans[u] = sum[mx];
    	if(!op) Update(u, ff, -1);
    }
    
    int main(){
    	n = Input();
    	for(RG int i = 1; i <= n; ++i) col[i] = Input(), first[i] = -1;
    	for(RG int i = 1; i < n; ++i){
    		RG int u = Input(), v = Input();
    		Add(u, v), Add(v, u);
    	}
    	Dfs(1, 0), Solve(1, 0, 1);
    	for(RG int i = 1; i <= n; ++i) printf("%lld ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    局部特征点检测 (Local Point Detector)
    算法
    64位编程
    QT开发之mock原理
    C#实现全角字符和半角字符转换
    QTableWidget基本功能总结(转)
    非const引用不能绑定非左值(nolvalue) .
    QTableWidget 应用总结
    QString和string类型相互转换(转)
    XML解析中文字符
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/9116072.html
Copyright © 2020-2023  润新知