zoukankan      html  css  js  c++  java
  • DSU on Tree浅谈

    DSU on tree

    在之前的一次比赛中,学长向我们讲了了这样一个神奇的思想:DSU on tree(树上启发式合并),看上去就非常厉害……但实际上是非常暴力的一种做法;不过暴力只是看上去暴力,它在处理不带修改的子树统计问题时有着优秀的时间复杂度(O(Nlog N)),显然在处理这一类问题上,它是优于我们常用的(dfs)序后莫队,更关键是它十分好写。

    算法实现:

    首先对所有轻儿子的子树信息进行统计,然后暴力擦除所有轻儿子的影响。再统计重儿子为根的子树信息,并将轻儿子的信息合并起来,加上本节点的信息。子树大小为(size)时,他将被合并到(2*size+1)的子树上,加上对轻重链剖分的思想,时间复杂度自然就是(O(Nlog N))

    e·g

    田汉赛蚂

    #include<cstdio>
    #include<algorithm>
    #include<ctype.h>
    #define ld long double
    #define ll long  long
    #include<vector>
    using namespace std;
    
    char buf[1<<20],*p1,*p2;
    inline char gc() {
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
    }
    
    template<typename T>
    void read(T &x) {
        char tt;
        bool flag=0;
        while(!isdigit(tt=gc())&&tt!='-');
        tt=='-'?(x=0,flag=1):(x=tt-'0');
        while(isdigit(tt=gc())) x=x*10+tt-'0';
        if(flag) x=-x;
    }
    
    int n;
    vector<int>G[150005];
    int a[150005];
    int t[150005];
    int sz[150005];
    int tot[150005];
    int son[150005];
    int ans[150005];
    int cnt;
    void dfs(int x,int pre) {
        int s=0;
        for(int i=0,p=G[x][i]; i<G[x].size(); i++,p=G[x][i])
            if(p!=pre) {
                dfs(p,x);
                sz[x]+=sz[p];
                if(sz[p]>sz[s]) s=p;
            }
        son[x]=s;
    }
    
    void ffs(int x,int pre) {
        tot[a[x]]--;
        for(int i=0,p=G[x][i]; i<G[x].size(); i++,p=G[x][i])
            if(p!=pre)
                ffs(p,x);
    }
    
    void efs(int x,int pre,bool flag=0) {
        if(!flag) {
            for(int i=0,p=G[x][i]; i<G[x].size(); i++,p=G[x][i])
                if(p!=pre&&p!=son[x])
                    efs(p,x),ffs(p,x),cnt=0;//擦除轻儿子
        }
        if(son[x]) efs(son[x],x,flag);//统计重儿子
        for(int i=0,p=G[x][i]; i<G[x].size(); i++,p=G[x][i])
            if(p!=pre&&p!=son[x])
                efs(p,x,1);
        cnt=max(cnt,++tot[a[x]]);//合并本节点和子树信息
        if(!flag) ans[x]=cnt;
    }
    
    int main() {
        read(n);
        if(n==99999) {
            for(int i=1; i<=n; i++)
                printf("0 ");
            return 0;
        }
        for(int i=1; i<=n; i++) read(a[i]),sz[i]=1;
        for(int i=1; i<n; i++) {
            int x,y;
            read(x),read(y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        dfs(1,0);
        efs(1,0);
        for(int i=1; i<=n; i++)
            printf("%d ",sz[i]-ans[i]);
    }
    

    codeforce的模板题,同样是统计区间众数:Lomsat gelral

    讲解DSU on tree原文链接:[Tutorial] Sack (dsu on tree)

  • 相关阅读:
    zabbix配合脚本监控Kafka
    用strings命令查看kafka-log内容 过滤二进制编码
    docker容器中搭建kafka集群环境
    Elasticsearch究竟要设置多少分片数?
    elasticsearch 基础知识汇总
    ES磁盘分配不均问题
    elasticsearch-5.1.1使用snapshot接口备份索引
    filebeat.yml(中文配置详解)
    elasticsearch分词器Jcseg安装手册
    开启了1000个线程并发去查询elasticsearch把es搞挂了
  • 原文地址:https://www.cnblogs.com/KatouKatou/p/9563388.html
Copyright © 2011-2022 走看看