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#操作REDIS例子
    A C# Framework for Interprocess Synchronization and Communication
    UTF8 GBK UTF8 GB2312 之间的区别和关系
    开源项目选型问题
    Mysql命令大全——入门经典
    RAM, SDRAM ,ROM, NAND FLASH, NOR FLASH 详解(引用)
    zabbix邮件报警通过脚本来发送邮件
    centos启动提示unexpected inconsistency RUN fsck MANUALLY
    rm 或者ls 报Argument list too long
    初遇Citymaker (六)
  • 原文地址:https://www.cnblogs.com/candy99/p/dsuontree.html
Copyright © 2011-2022 走看看