dsu on tree简介及例题

dsu on tree简介及例题dsu nbsp on nbsp treedsu on treedsu nbsp on nbsp tree 树上启发式合并 多用于对子树的暴力询问 通过使用轻重链定义来进行优化 将算法复杂度降到 O nlogn O nlogn O nlogn 算是一种优雅的暴力先用一道 dsuontree 比较模版的题来引一下 codeforces60 题意 一棵树 n 个点 每个点有一个颜色要求每个结点子树的出现哪个颜色次数最多如果有多个颜色次数同时最多 结果为这些颜色编号相加首先可以考虑暴力的写


d s u   o n   t r e e dsu ~on ~tree dsu on tree
树上启发式合并,多用于对子树的暴力询问,通过使用轻重链定义来进行优化,将算法复杂度降到 O ( n l o g n ) O(nlogn) O(nlogn)
算是一种优雅的暴力





一棵树n个点,每个点有一个颜色 要求每个结点子树的出现哪个颜色次数最多 如果有多个颜色次数同时最多,结果为这些颜色编号相加



原理

引入一个结论:从某一个点到根的路径中轻链的个数不会超过 l o g n logn logn

证明:
从一个结点开始往上到根的过程中,每次交汇到一个点,如果这个点是轻链,那么这个点的子节点数一定比重链的少,假设这个轻链对应子树结点大小为 y y y,这个交汇点子树结点大小为 x x x,那么 y < x / 2 y
y<x/2

如果这个点到根上有z个轻链,那么需要交汇z次
那么这个点的子树结点个数会成为 n u m < = n 2 z num<=\frac{n}{2^z} num<=2zn
n u m > = 1 num>=1 num>=1,所以 z < l o g n z
z<logn








并且,由于递归的性质,每次在递归return之后会回到一个父亲,那么在返回的时候,我们之前算的子树完全可以保留一个回到父亲节省下次计算,那么,我们每次最后访问重儿子,并且把重儿子的贡献保留传递给父亲继续计算,然后把轻儿子暴力计算,通过这个结论我们可以发现这样的复杂度最后只会达到 O ( n l o g n ) O(nlogn) O(nlogn)


算法

可以简化为如下的模版:

int sz[N], son[N]; vector<int> g[N]; void dfs(int u, int fa) { 
         sz[u] = 1; for (auto v : g[u]) { 
         if (v == fa) continue; dfs(v, u); sz[u] += sz[v]; if (sz[v] > sz[son[u]]) son[u] = v; } } int Son; //add函数为计算贡献的方法 void add(int u, int fa, int val) { 
         } void dfs1(int u, int fa, int op) { 
         for (auto v : g[u]) { 
         if (v == fa || v == son[u]) continue; dfs1(v, u, 0); } if (son[u]) dfs1(son[u], u, 1), Son = son[u]; add(u, fa, 1) Son = 0; if (!op) add(u, fa, -1); } 

这样就形成了一个模版


例题

1. Lomsat gelral(引题)

/* Author : zzugzx Lang : C++ Blog : blog.csdn.net/_ */ #include 
           using namespace std; #define fi first #define se second #define pb push_back #define mp make_pair #define all(x) (x).begin(), (x).end() #define endl '\n' #define SZ(x) (int)x.size() #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; typedef pair<ll, ll> pll; //const int mod = 1e9 + 7; const int mod = ; const double eps = 1e-8; const double pi = acos(-1.0); const int maxn = 1e6 + 10; const int N = 1e2 + 10; const ll inf = 0x3f3f3f3f; const ll oo = 8e18; const int dir[][2]={ 
         { 
         0, 1}, { 
         1, 0}, { 
         0, -1}, { 
         -1, 0}, { 
         1, 1}, { 
         1, -1}, { 
         -1, 1}, { 
         -1, -1}}; int col[maxn], sz[maxn], son[maxn]; vector<int> g[maxn]; void dfs(int u, int fa) { 
          sz[u] = 1; for (auto v : g[u]) { 
          if (v == fa) continue; dfs(v, u); sz[u] += sz[v]; if (sz[v] > sz[son[u]]) son[u] = v; } } ll ans[maxn], sum, cnt[maxn], Son, mx; void add(int u, int fa, int val) { 
          cnt[col[u]] += val; if (cnt[col[u]] > mx) { 
          mx = cnt[col[u]]; sum = col[u]; } else if (cnt[col[u]] == mx) { 
          sum += col[u]; } for (auto v : g[u]) { 
          if (v == fa || v == Son) continue; add(v, u, val); } } void dfs1(int u, int fa, int op) { 
          for (auto v : g[u]) { 
          if (v == fa || v == son[u]) continue; dfs1(v, u, 0); } if (son[u]) dfs1(son[u], u, 1), Son = son[u]; add(u, fa, 1); Son = 0; ans[u] = sum; if (!op) add(u, fa, -1), sum = 0, mx = 0; } int main() { 
          ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); int n; cin >> n; for (int i = 1; i <= n; i++) cin >> col[i]; for (int i = 1; i < n; i++) { 
          int u, v; cin >> u >> v; g[u].pb(v); g[v].pb(u); } dfs(1, 0); dfs1(1, 0, 0); for (int i = 1; i <= n; i++) cout << ans[i] << ' '; return 0; } 

2.Tree Requests

/* Author : zzugzx Lang : C++ Blog : blog.csdn.net/_ */ #include 
           using namespace std; #define fi first #define se second #define pb push_back #define mp make_pair #define all(x) (x).begin(), (x).end() #define endl '\n' #define SZ(x) (int)x.size() #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; typedef pair<ll, ll> pll; //const int mod = 1e9 + 7; const int mod = ; const double eps = 1e-8; const double pi = acos(-1.0); const int maxn = 5e5 + 10; const int N = 1e2 + 10; const ll inf = 0x3f3f3f3f; const ll oo = 8e18; const int dir[][2]={ 
         { 
         0, 1}, { 
         1, 0}, { 
         0, -1}, { 
         -1, 0}, { 
         1, 1}, { 
         1, -1}, { 
         -1, 1}, { 
         -1, -1}}; char c[maxn]; int sz[maxn], son[maxn], dep[maxn]; vector<int> g[maxn]; vector<pii> qry[maxn]; void dfs(int u, int fa) { 
          sz[u] = 1, dep[u] = dep[fa] + 1; for (auto v : g[u]) { 
          if (v == fa) continue; dfs(v, u); sz[u] += sz[v]; if (sz[v] > sz[son[u]]) son[u] = v; } } bool ans[maxn]; int cnt[maxn][26], Son; void add(int u, int fa, int val) { 
          cnt[dep[u]][c[u] - 'a'] += val; for (auto v : g[u]) { 
          if (v == fa || v == Son) continue; add(v, u, val); } } bool check(int x) { 
          int res = 0; for (int i = 0; i < 26; i++) if (cnt[x][i] & 1) res++; return res <= 1; } void dfs1(int u, int fa, int op) { 
          for (auto v : g[u]) { 
          if (v == fa || v == son[u]) continue; dfs1(v, u, 0); } if (son[u]) dfs1(son[u], u, 1), Son = son[u]; add(u, fa, 1); Son = 0; for (auto i : qry[u]) { 
          int id = i.se, d = i.fi; if (check(d)) ans[id] = 1; else ans[id] = 0; } if (!op) add(u, fa, -1); } int main() { 
          ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); int n, _; cin >> n >> _; for (int i = 2; i <= n; i++) { 
          int x; cin >> x; g[x].pb(i); g[i].pb(x); } for (int i = 1; i <= n; i++) cin >> c[i]; for (int i = 1; i <= _; i++) { 
          int v, h; cin >> v >> h; qry[v].pb({ 
         h, i}); } dfs(1, 0); dfs1(1, 0, 0); for (int i = 1; i <= _; i++) if (ans[i]) cout << "Yes" << endl; else cout << "No" << endl; return 0; } 

3.Strange Memory

/* Author : zzugzx Lang : C++ Blog : blog.csdn.net/_ */ #include 
           using namespace std; #define fi first #define se second #define pb push_back #define mp make_pair #define all(x) (x).begin(), (x).end() #define endl '\n' #define SZ(x) (int)x.size() #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; typedef pair<ll, ll> pll; //const int mod = 1e9 + 7; const int mod = ; const double eps = 1e-8; const double pi = acos(-1.0); const int maxn = 1e6 + 10; const int N = 1e5 + 10; const ll inf = 0x3f3f3f3f; const ll oo = 8e18; const int dir[][2]={ 
         { 
         0, 1}, { 
         1, 0}, { 
         0, -1}, { 
         -1, 0}, { 
         1, 1}, { 
         1, -1}, { 
         -1, 1}, { 
         -1, -1}}; int sz[N], son[N], a[N]; vector<int> g[N]; void dfs(int u, int fa) { 
          sz[u] = 1; for (auto v : g[u]) { 
          if (v == fa) continue; dfs(v, u); sz[u] += sz[v]; if (sz[v] > sz[son[u]]) son[u] = v; } } ll ans; int cnt[][18][2], Son; void calc(int u, int fa, int w) { 
          for (int i = 0; i < 18; i++) ans += (1ll << i) * cnt[a[u] ^ w][i][!((u >> i) & 1)]; for (auto v : g[u]) { 
          if (v == fa || v == Son) continue; calc(v, u, w); } } void add(int u, int fa, int val) { 
          for (int i = 0; i < 18; i++) cnt[a[u]][i][(u >> i) & 1] += val; for (auto v : g[u]) { 
          if (v == fa || v == Son) continue; add(v, u, val); } } void dfs1(int u, int fa, int op) { 
          for (auto v : g[u]) { 
          if (v == fa || v == son[u]) continue; dfs1(v, u, 0); } if (son[u]) dfs1(son[u], u, 1), Son = son[u]; for (auto v : g[u]) { 
          if (v == fa || v == Son) continue; calc(v, u, a[u]); add(v, u, 1); } for (int i = 0; i < 18; i++) cnt[a[u]][i][(u >> i) & 1] += 1; Son = 0; if (!op) add(u, fa, -1); } int main() { 
          ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i < n; i++) { 
          int u, v; cin >> u >> v; g[u].pb(v); g[v].pb(u); } dfs(1, 0); dfs1(1, 0, 0); cout << ans << endl; return 0; } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/221469.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午6:01
下一篇 2026年3月17日 下午6:02


相关推荐

  • plsqldev设置中文_plsql13安装以及配置

    plsqldev设置中文_plsql13安装以及配置1、查看服务端编码selectuserenv(‘language’)fromdual;然后将查询到的服务器编码,配置到环境变量,保证客户端与服务器端编码一致。2、配置环境变量计算机–>右键属性–>高级系统设置–>环境变量–>系统变量,新建…

    2025年7月8日
    13
  • spring事务的默认隔离级别_事务隔离级别有哪些

    spring事务的默认隔离级别_事务隔离级别有哪些目录1、前言2、验证结论3、总结1、前言事务的四个隔离级别想必大家都已经清楚,但是在学习Spring的时候,我们发现Spring自己也有四个隔离级别(加上默认的是五个)。那么问题来了,当Spring设置的隔离级别和我们在数据库设置的隔离级别不一致时,哪个会生效?先抛出结论:Spring设置的隔离级别会生效2、验证结论要验证结论很简单,我们只需要在spring事务注解上面配置不同的隔离级别就行了:DAO层实现类的两个方法pay方法是模拟事务A先查询一次数据,然后休眠两秒再查询一次数据

    2025年11月11日
    5
  • win10无法运行bat命令_windows2012执行bat

    win10无法运行bat命令_windows2012执行batwindow环境下,通过DOS命令模式,调用bat脚本,执行jar包。可以正常打印jar包中的日志都指定日志文件。通过tomcat部署的某服务去调用时出现不可调用,也不打印日志问题。分两步来确定问题:1、参数是否传递给bat脚本;2、bat脚本中的java-jar是否正常执行了;问题1通过,在bat脚本入口处增加echoname:%1age:%2&gt;&g…

    2026年2月25日
    4
  • Oracle 11g安装图文攻略「建议收藏」

    Oracle 11g安装图文攻略「建议收藏」Oracle11g****安装图文攻略一、Oracle下载注意Oracle分成两个文件,下载完后,将两个文件解压到同一目录下即可。路径名称中,最好不要出现中文,也不要出现空格等不规则字符。官方下地址:http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html以下两网址来源此官方下载页网。win32位操作系统下载地址:http://download.oracle.com/otn/nt

    2026年2月8日
    6
  • Anaconda+Pycharm环境下的PyTorch配置方法

    Anaconda+Pycharm环境下的PyTorch配置方法写给新手的话 pycharm 是什么 为什么让我指定 interpreter 记事本最开始写 C 语言代码的时候 人们使用 vi 记事本等软件写代码 写完了之后用 GCC 编译 然后运行编译结果 就是二进制文件 python 也可以这样做 用记事本写完代码 保存成如 test py 的文件后 通过命令 pythontest py 可以运行这一文件 最初的 C 语言代码都是通过这种方式写的 但是人们很快发现了一个问题 就是

    2026年3月27日
    2
  • Python调用百度云api,实现截图图片文字识别

    Python调用百度云api,实现截图图片文字识别调用百度云api,实现截图图片文字识别相信大家在网上查找资料时都会遇到一些类似于pdf格式的文档,无法直接复制,手打太过于浪费时间。那么在这里我分享一个调用百度云api文字识别接口识别此类文字的python小程序。本人刚学习python时间不长,如果内容有错误还望斧正。首先我们需要去百度云官网申请一个接口点击立即使用创建应用填写需要填写的数据后点击立即创建,即可创建成功此时我们…

    2022年6月1日
    45

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号