这个属于一种技巧,可以解决类似于子树询问无修改可离线的问题,一些点分治的问题也可以用Dsu on Tree解决,并且常数较小,代码复杂度低,很具有可写性。

整体上的意思就是继承重儿子的信息,暴力修改轻儿子的信息,时间复杂度的证明类似并查集的启发式合并(本质上这个就是启发式合并)。

通常情况下,题目长成询问某种东西的数量,或者某种点对的数量。

例题时间

Educational Codeforces Round 2 E Lomsat gelral

$n$个点的有根树,以$1$为根,每个点有一种颜色。我们称一种颜色占领了一个子树当且仅当没有其他颜色在这个子树中出现得比它多。求占领每个子树的所有颜色之和。

莫队可以解决这个问题,想写莫队的可以叉掉这个网页然后去AC了。

那么我们考虑用Dsu on Tree解决这个问题。

我们要做的是为何一个和,和一个最大值还有一个桶,那么,把对应的维护出来,然后暴力更新即可。

你说不会?暴力会不会?就是暴力啊...如果还不会那么就看代码吧...

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
using namespace std;
#define N 100005
struct node{int to,next;}e[N<<1];
int head[N],val[N],col[N],maxx,siz[N],son[N],n,cnt;long long ans[N],sum;
void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;}
void dfs1(int x,int from)
{
siz[x]=1;
for(int i=head[x];i!=-1;i=e[i].next)
{
int to1=e[i].to;
if(to1!=from)dfs1(to1,x),siz[x]+=siz[to1],son[x]=(siz[to1]>siz[son[x]]?to1:son[x]);
}
}
void add(int x,int from,int c)
{
col[val[x]]+=c;
if(col[val[x]]>=maxx&&c>0)
{
if(col[val[x]]>maxx)maxx=col[val[x]],sum=0;
sum+=val[x];
}
for(int i=head[x];i!=-1;i=e[i].next)
{
int to1=e[i].to;
if(to1!=from)add(to1,x,c);
}
}
void dfs2(int x,int from,int op)
{
for(int i=head[x];i!=-1;i=e[i].next)
{
int to1=e[i].to;
if(to1!=from&&to1!=son[x])dfs2(to1,x,0);
}if(son[x])dfs2(son[x],x,1);
for(int i=head[x];i!=-1;i=e[i].next)
{
int to1=e[i].to;
if(to1!=from&&to1!=son[x])add(to1,x,1);
}
col[val[x]]++;
if(col[val[x]]>=maxx)
{
if(col[val[x]]>maxx)maxx=col[val[x]],sum=0;
sum+=val[x];
}
ans[x]=sum;
if(!op)add(x,from,-1),sum=0,maxx=0;
}
int main()
{
scanf("%d",&n);memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)scanf("%d",&val[i]);
for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs1(1,0);dfs2(1,0,1);
for(int i=1;i<=n;i++)printf("%lld ",ans[i]);return 0;
}

  

Codeforces Round #383 (Div. 1) D

我们称一个字符串为doubi string当且仅当重排它的字符可以组成一个回文串。

给出一个$n$个点的有根树,根为$1$,每条边上有一个字符(只有$a \sim v$,别问我为什么),求每个点的子树中所有简单路径可以组成的doubi string中的最长长度。

这个题其实求的就是树上的一条最大只有一个字母出现了奇数次的最长链。

然后维护一下$s_i$表示$i$到根的字符状态,然后每次将轻重儿子信息合并的时候更新答案。

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
using namespace std;
#define N 500005
struct node{int to,next;}e[N<<1];
int head[N],siz[N],cnt,n,S[1<<23],val[N],son[N],dep[N],ans[N],tmp_ans;
void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;}
void dfs1(int x,int from)
{
dep[x]=dep[from]+1,siz[x]=1,val[x]^=val[from];
for(int i=head[x];i!=-1;i=e[i].next)
{
int to1=e[i].to;
if(to1!=from)dfs1(to1,x),siz[x]+=siz[to1],son[x]=(siz[to1]>siz[son[x]]?to1:son[x]);
}
}
#define change(x) S[val[x]]=max(dep[x],S[val[x]]);
void add(int x,int from,bool op)
{
if(op)S[val[x]]=max(dep[x],S[val[x]]);
else S[val[x]]=-0x3f3f3f3f;
for(int i=head[x];i!=-1;i=e[i].next)
{
int to1=e[i].to;
if(to1!=from)add(to1,x,op);
}
}
void get(int x)
{
tmp_ans=max(tmp_ans,S[val[x]]+dep[x]);
for(int i=0;i<=22;i++)tmp_ans=max(tmp_ans,S[val[x]^(1<<i)]+dep[x]);
}
void get_ans(int x,int from)
{
get(x);
for(int i=head[x];i!=-1;i=e[i].next)
{
int to1=e[i].to;
if(to1!=from)get_ans(to1,x);
}
}
void dfs2(int x,int from,int op)
{
for(int i=head[x];i!=-1;i=e[i].next)
{
int to1=e[i].to;
if(to1!=from&&to1!=son[x])dfs2(to1,x,0);
}if(son[x])dfs2(son[x],x,1),ans[x]=ans[son[x]];
for(int i=head[x];i!=-1;i=e[i].next)
{
int to1=e[i].to;
if(to1!=from&&to1!=son[x])
get_ans(to1,x),ans[x]=max(ans[x],ans[to1]),add(to1,x,1);
}get(x);change(x);
// printf("%d\n",x);
// for(int i=1;i<(1<<23);i++)if(S[i]>0)printf("%d ",i);puts("");
ans[x]=max(ans[x],tmp_ans-(dep[x]<<1)),tmp_ans=0;
if(!op)add(x,from,0);
}char rr[2];
int main()
{
scanf("%d",&n);memset(head,-1,sizeof(head));memset(S,-0x3f,sizeof(S));
for(int i=2,x;i<=n;i++)scanf("%d%s",&x,rr),val[i]=1<<(rr[0]-'a'),add(x,i),add(i,x);
dfs1(1,0);dfs2(1,0,1);for(int i=1;i<=n;i++)printf("%d ",ans[i]);return 0;
}

  

Dsu on Tree的更多相关文章

  1. CF 741D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths [dsu on tree 类似点分治]

    D. Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths CF741D 题意: 一棵有根树,边上有字母a~v,求每个子树中最长的边,满 ...

  2. CF 570D. Tree Requests [dsu on tree]

    传送门 题意: 一棵树,询问某棵子树指定深度的点能否构成回文 当然不用dsu on tree也可以做 dsu on tree的话,维护当前每一个深度每种字母出现次数和字母数,我直接用了二进制.... ...

  3. [dsu on tree]【学习笔记】

    十几天前看到zyf2000发过关于这个的题目的Blog, 今天终于去学习了一下 Codeforces原文链接 dsu on tree 简介 我也不清楚dsu是什么的英文缩写... 就像是树上的启发式合 ...

  4. CF 375D. Tree and Queries【莫队 | dsu on tree】

    题意: 一棵树,询问一个子树内出现次数$≥k$的颜色有几种 强制在线见上一道 用莫队不知道比分块高到哪里去了,超好写不用调7倍速度!!! 可以用分块维护出现次数这个权值,实现$O(1)-O(\sqrt ...

  5. dsu on tree 树上启发式合并 学习笔记

    近几天跟着dreagonm大佬学习了\(dsu\ on\ tree\),来总结一下: \(dsu\ on\ tree\),也就是树上启发式合并,是用来处理一类离线的树上询问问题(比如子树内的颜色种数) ...

  6. UOJ#266. 【清华集训2016】Alice和Bob又在玩游戏 博弈,DSU on Tree,Trie

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ266.html 题解 首先我们可以直接暴力 $O(n^2)$ 用 sg 函数来算答案. 对于一个树就是枚举 ...

  7. dsu on tree入门

    先瞎扯几句 说起来我跟这个算法好像还有很深的渊源呢qwq.当时在学业水平考试的考场上,题目都做完了不会做,于是开始xjb出题.突然我想到这么一个题 看起来好像很可做的样子,然而直到考试完我都只想出来一 ...

  8. 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree

    原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...

  9. [Codeforces741D]Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths——dsu on tree

    题目链接: Codeforces741D 题目大意:给出一棵树,根为$1$,每条边有一个$a-v$的小写字母,求每个点子树中的一条最长的简单路径使得这条路径上的边上的字母重排后是一个回文串. 显然如果 ...

  10. BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)

    BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...

随机推荐

  1. 如何用JS获取页面上的所有标签

    最近忙的一匹,忙着大保健,都来不及写博客,今天特意抽出点时间来写一写 前两天看到一个题,是问如何从页面上获取所有的标签的并查看他们的数量,感觉还是有点意思的,所以给大家来搞一下子 我们先来捋捋思路,那 ...

  2. kotlin3-IdeaIU编辑器字体自动放大缩小

  3. SD从零开始59-61,跨公司的库存转移,Interface 修改,可用性检查和需求传递

    [原创]SD从零开始59 跨公司的库存转移处理流程 库存转移流程Stock Transfer Procedure 2个工厂间的库存转移能够使用不同的流程来执行: 只执行一个库存转移记账的流程使用MM库 ...

  4. CADO SAP tcode - Time Sheet: Display Data

    CADO (Time Sheet: Display Data) is a standard SAP transaction code available within R/3 SAP systems ...

  5. nginx深入剖析

    1.nginx功能模块说明 nginx之所以很强大,是因为具有很多的强大的模块 nginx核心功能模块:nginx的核心功能模块负责nginx的全局应用,主要对应的是主配置文件中的Main区块和Eve ...

  6. Array常用方法总结

    一.[常用语法] 1.1.数组的创建var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定 ...

  7. Hibernate Criteria用法大全

    1.标准查询简介 2.比较运算符 3.分页使用标准 4.排序结果 5.预测与聚合 6.关联 7. 动态关联抓取 8.查询示例 9.投影(Projections).聚合(aggregation)和分组( ...

  8. SQLSERVER中的LOB页面简单研究

    SQLSERVER中的LOB页面简单研究 这篇文章和我另一篇文章是相辅相成的,在看<SQLSERVER2012 列存储索引的简单研究和测试>这篇文章之前希望大家先看一下这篇文章o(∩_∩) ...

  9. Azure 中的虚拟网络和虚拟机

    创建 Azure 虚拟机 (VM) 时,必须创建虚拟网络 (VNet) 或使用现有的 VNet. 此外,还需要确定如何在 VNet 上访问 VM. 在创建资源之前必须做好规划,确保了解网络资源的限制. ...

  10. Java 如何启用 ARM 虚拟机诊断

    现象描述 如何通过 Java 语言实现在创建 ARM 虚拟机时开启诊断,并配置相关指标.   实现思路 调研最高版本的 JAVA SDK(1.1.0)源码发现,SDK 层面并未提供任启动诊断和配置诊断 ...