首页 > 其他分享 >dsu on tree 学习笔记

dsu on tree 学习笔记

时间:2023-06-28 17:44:24浏览次数:50  
标签:fath int dsu tree 笔记 儿子 edge ans col

dsu on tree 学习笔记

引入

dsu 是并查集的缩写,然鹅本算法和并查集没啥关系。当然,dsu on tree 也有中文名字:树上启发式合并。也就是说,这个算法是用于处理一些树上信息的合并的。

dsu on tree 和莫队一样,都是优雅的暴力。优雅是因为思想很优雅,暴力是因为所有修改都是暴力做的——没错,遍历整棵子树的那种暴力。

思想

当然,虽然是暴力,直接搞肯定会 T。既然是要合并信息,我们肯定是要能少删除就少删除,也就是说,保留信息最多的,让其他信息往上合并。

dsu on tree 利用了重链剖分的一个性质来实现这一点。我们每次都先处理轻儿子,再把轻儿子的信息删除,然后再处理重儿子,保留重儿子信息的同时再去暴力把轻儿子的信息求出来,以达到求出这一棵子树中所有节点答案的目的。

看着很暴力,但是实际上,这样做的复杂度只有 \(O(n \log_n)\)!为什么呢?我们知道,在重链剖分中,每一个轻儿子最多跳 \(\log_n\) 条轻边就会跳到重链上。我们可以反过来想:轻儿子的信息什么时候不用被清空呢?也就是当轻儿子所在的重儿子(就是重链上的一部分)被处理到时。那么,我们有这样一个结论:每一个节点的信息最多被清空 \(\log_n\) 次,最终的复杂度就是 \(O(n \log_n)\)。

例题

CF600E Lomsat gelral

模板题,具体见代码注释。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+100;

inline int read(){
    int x = 0; char ch = getchar();
    while(ch<'0' || ch>'9') ch = getchar();
    while(ch>='0'&&ch<='9') x = x*10+ch-48, ch = getchar();
    return x;
}
int head[N], tot;
struct node{
    int nxt, to;
}edge[N<<1];
void add(int u, int v){
    edge[++tot].nxt = head[u];
    edge[tot].to = v;
    head[u] = tot;
}

int col[N];
int n;

long long vis[N];
long long sum_ans, now_ans;
long long ans[N];

int siz[N], son[N];
void dfs1(int u, int fath){//和树链剖分的dfs1基本一样,求出重儿子
    siz[u] = 1;
    for(int i = head[u]; i; i = edge[i].nxt){
        int v = edge[i].to;
        if(v == fath) continue;
        dfs1(v, u);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v]) son[u] = v;
    }
}

void update(int u, int fath){//增加信息,更新答案
    vis[col[u]]++;
    if(vis[col[u]]>sum_ans) now_ans =col[u], sum_ans = vis[col[u]];
    else if(vis[col[u]]==sum_ans) now_ans+=col[u];//可能有不止一种优势颜色
    for(int i = head[u]; i; i = edge[i].nxt){
        int v = edge[i].to;
        if(v == fath){
            continue;
        }
        update(v, u);
    }
}

void del(int u, int fath){//删除信息,清空轻儿子的贡献
    vis[col[u]]--;
    for(int i = head[u]; i; i = edge[i].nxt){
        int v = edge[i].to;
        if(v == fath){
            continue;
        }
        del(v, u);
    }
}
void dfs(int u, int fath, bool op){
    for(int i = head[u]; i; i = edge[i].nxt){
        int v = edge[i].to;
        if((fath ^ v)&&(son[u] ^ v)){
            dfs(v, u, 1);
        }//先搞轻儿子
    }
    if(son[u]) dfs(son[u], u, 0);//最后搞重儿子
    vis[col[u]]++;//注意当前节点的贡献不要忘了加上
    if(vis[col[u]]>sum_ans) now_ans =col[u], sum_ans = vis[col[u]];
    else if(vis[col[u]]==sum_ans) now_ans+=col[u];

    for(int i = head[u]; i; i = edge[i].nxt){//此时重儿子已经处理好且信息未删除,现在把轻儿子的贡献合并上来
        int v = edge[i].to;
        if((v ^ fath) && (v ^ son[u])){
            update(v, u);
        }
    }
    ans[u] = now_ans;//记录答案
    if(op) now_ans = sum_ans = 0, del(u, fath);//如果是轻儿子就清空当前子树的贡献
}
int main(){
    n = read();
    for(int i = 1; i<=n; ++i) col[i] = read();
    for(int i = 1; i<n; ++i){
        int u = read(), v = read();
        add(u, v);
        add(v, u);
    }
    dfs1(1, 0);
    dfs(1, 0, 0);
    for(int i = 1; i<=n; ++i){
        printf("%lld", ans[i]);
        if(i<n) putchar(' ');
        else putchar('\n');
    }
    return 0;
}

标签:fath,int,dsu,tree,笔记,儿子,edge,ans,col
From: https://www.cnblogs.com/frostwood/p/17512092.html

相关文章

  • win10上sourcetree打开闪一下无法启动
    sourcetree突然无法启动,找到以下目录C:\Users\ASUS\AppData\Local\Atlassian\SourceTree.exe_Url_tufs0rwdi0w3ctjvjcuakubjhrh2c4XX\3.2.6.3544删除目录下的Composition.cache文件,再次打开可以重新启动 参考:https://blog.csdn.net/weixin_45643338/article/details/1312119......
  • 2023年最新Android Framework源码高级笔记+学习路线图+硬核资料库,跪着啃完了。。。
    虽然疫情已经过去,餐饮、旅游一些实体经济迅速回暖,但是互联网的寒冬却还没有过去,很多大厂都在裁员,裁员比例还挺高,我们一千多人的公司就直接裁掉30%。今年的各大公司基本只有两个目标:一个是营收,那些投入产出比不高的项目或者事情都暂时搁置,可做可不做的就不做;另外一个就是降本增效,通......
  • 软测笔记4-【Linux系统】
    一、Linux系统介绍1.操作系统定义:管理计算机硬件与软件资源的计算机程序,同时也是计算机系统的内核与基石2.常见操作系统a.桌面操作系统Windows系列LinuxMacOSb.嵌入式操作系统Linuxc.服务器操作系统LinuxUnixWindowsServerd.移动设备操作系统Android(Linux)IOS(Linux)......
  • Coloring Tree (牛客多校) (BFS序列妙用+ f(n)-f(n+1)+ 组合数学)
    题目大意:给一个树,然后有k种颜色可以给树上色权值是2个相同颜色节点的最短距离问让权值为D的方案数 题解:首先要让2个节点为D,怎么处理呢?利用f(D)-f(D+1)即可因为问的是2个相同颜色点的最短距离,因此直接bfs用一个bfs序列然后在bfs一下,因为之前co......
  • 【Flutter专题】Android Flutter入门笔记、技术解析与项目实战
    Flutter是一个跨平台、高性能的移动UI框架,其采用Dart语言开发,并使用自己的渲染引擎来绘制UI,保证了自身的高性能,保证了在Android和iOS上UI的一致性。目前Flutter已经支持iOS、Android、Web、Windows、macOS、Linux、Fuchsia(Google新的自研操作系统)等众多平台。与其他跨平......
  • Android知识笔记:记录 2 个 “容易误解” 的Android 知识点
    今天分享两个之前我们可能都搞错的Android知识点,我们还是要追求极致,把不懂的问题搞懂的~1.事件到底是先到DecorView还是先到Window的?有天早上看到事件分发的一个讨论:那么事件到底是先到DecorView还是先到Window(Activity,Dialog)的呢,引发出两个问题:1.touch相关事件在DecorView,Phon......
  • Same Tree
    Giventherootsoftwobinarytreespandq,writeafunctiontocheckiftheyarethesameornot.Twobinarytreesareconsideredthesameiftheyarestructurallyidentical,andthenodeshavethesamevalue.Solution:classSolution:defisSameTre......
  • css grid布局(网格布局)笔记
    Grid布局网格布局的基本概念CSS网格布局引入了二维网格布局系统,可用于布局页面主要的区域布局或小型组件。什么是网格?网格是一组相交的水平线和垂直线,它定义了网格的列和行。我们可以将网格元素放置在与这些行和列相关的位置上。网格布局的特点:固定的轨道尺寸或者弹性......
  • el-tree 树的全部展开和收起
      https://blog.csdn.net/weixin_46156770/article/details/122696483......
  • 真·随笔(三)《政治学通识》笔记
    读书太少了,还天天鉴证,没底子。看点东西充实一下。中国政治观:中国古代(孔子、韩非)、海国图志、孙中山、当代。孙:管理众人的事便是政治。孔子对曰:“政者,正也。子帅以正,孰敢不正?”……翻译成现代政治学语言,可以表述为“政府是社会的道德榜样”。借助这种视角,大家可以理解目前中国......