zoukankan      html  css  js  c++  java
  • [dsu on tree]【学习笔记】

    十几天前看到zyf2000发过关于这个的题目的Blog, 今天终于去学习了一下 [Codeforces原文链接](http://codeforces.com/blog/entry/44351#comment-332425)

    dsu on tree

    简介

    我也不清楚dsu是什么的英文缩写...
    好吧是Disjoint Set Union 并查集2333
    就像是树上的启发式合并
    用到了(heavy-light decomposition)树链剖分
    把轻边子树的信息合并到重链上的点里
    因为每次都是先dfs轻儿子再dfs重儿子,只有重儿子子树的贡献保留,所以可以保证dfs到每颗子树时当前全局维护的信息不会有别的子树里的,和莫队很像


    算法过程

    find the BigChild of each vertex
    dfs(u, fa, keep)
        dfs(LightChild, u, 0)
        dfs(BigChild, u, 1), big[BigChild] = 1
        update(u, fa, 1) //calculate the contribution of u's LightChild's SubTree
        update the ans of u
        big[BigChild] = 0
        if keep == 0 
            update(u, fa, -1) //remove the contributino of u's SubTree
            
    update(u, fa, val)
        calculate u's information
        update(v : (u, v) and !big[v], u, val)
        
    

    先递归计算轻儿子子树,递归结束时消除他们的贡献
    再递归计算重儿子子树,保留他的贡献
    再计算当前子树中所有轻子树的贡献
    更新答案
    如果当前子树是父节点的轻子树,消除当前子树的贡献


    复杂度分析

    显然只有遇到轻边才会把自己的信息合并到父节点
    树链剖分后每个点到根的路径上有(logn)条轻边和(lgon)条重链
    一个点的信息只会向上合并(logn)
    如果一个点的信息修改是(O(1))的,那么总复杂度就是(O(nlogn))
    从这里我们可以发现和对dfs序使用莫队有异曲同工之妙,莫队也要求修改的复杂度很低


    应用

    1. 优秀的dfs序莫队替代品,复杂度(sqrt{n} ightarrow logn)
    2. 结合点分治的思想可以做一些有根树上的路径统计问题

    模板题

    CF600E. Lomsat gelral
    题意:询问每颗子树中出现次数最多的颜色们编号和

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    #define pii pair<int, ll>
    #define MP make_pair 
    #define fir first
    #define sec second
    const int N=1e5+5;
    int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    
    int n, a[N];
    struct edge{int v, ne;}e[N<<1];
    int cnt, h[N];
    inline void ins(int u, int v) {
    	e[++cnt]=(edge){v, h[u]}; h[u]=cnt;
    	e[++cnt]=(edge){u, h[v]}; h[v]=cnt;
    }
    int size[N], mx[N], big[N];
    void dfs(int u, int fa) {
    	size[u]=1;
    	for(int i=h[u];i;i=e[i].ne) 
    		if(e[i].v != fa) {
    			dfs(e[i].v, u);
    			size[u] += size[e[i].v];
    			if(size[e[i].v] > size[mx[u]]) mx[u] = e[i].v;
    		}
    }
    
    int cou[N], Max; ll ans[N];
    pii f[N];
    void update(int u, int fa, int val) {
    	int &c = cou[a[u]];
    	f[c].fir --; f[c].sec -= a[u];
    	c += val;
    	f[c].fir ++; f[c].sec += a[u];
    	if(val==1) Max = max(Max, c);
    	else if(!f[Max].fir) Max--;
    
    	for(int i=h[u];i;i=e[i].ne) 
    		if(e[i].v != fa && !big[e[i].v]) update(e[i].v, u, val);
    }
    
    void dfs(int u, int fa, int keep) {
    	for(int i=h[u];i;i=e[i].ne) 
    		if(e[i].v != fa && e[i].v != mx[u]) dfs(e[i].v, u, 0);
    	if(mx[u]) dfs(mx[u], u, 1), big[mx[u]] = 1;
    	update(u, fa, 1);
    	ans[u] = f[Max].sec;
    	big[mx[u]] = 0;
    	if(!keep) update(u, fa, -1);
    }
    int main() {
    	//freopen("in","r",stdin);
    	n=read();
    	for(int i=1; i<=n; i++) a[i]=read();
    	for(int i=1; i<n; i++) ins(read(), read());
    	dfs(1, 0);
    	dfs(1, 0, 1);
    	for(int i=1; i<=n; i++) printf("%I64d ",ans[i]);
    }
    
    

  • 相关阅读:
    C# 实现 Snowflake算法生成唯一性Id
    kafka可视化客户端工具(Kafka Tool)的基本使用(转)
    docker 安装kafka
    Model类代码生成器
    使用docker 部署rabbitmq 镜像
    Vue 增删改查 demo
    git 提交代码到库
    Android ble蓝牙问题
    mac 配置 ssh 到git (Could not resolve hostname github.com, Failed to connect to github.com port 443 Operation timed out)
    okhttp
  • 原文地址:https://www.cnblogs.com/candy99/p/dsuontree.html
Copyright © 2011-2022 走看看