Dsu on Tree
这个属于一种技巧,可以解决类似于子树询问无修改可离线的问题,一些点分治的问题也可以用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的更多相关文章
- 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,求每个子树中最长的边,满 ...
- CF 570D. Tree Requests [dsu on tree]
传送门 题意: 一棵树,询问某棵子树指定深度的点能否构成回文 当然不用dsu on tree也可以做 dsu on tree的话,维护当前每一个深度每种字母出现次数和字母数,我直接用了二进制.... ...
- [dsu on tree]【学习笔记】
十几天前看到zyf2000发过关于这个的题目的Blog, 今天终于去学习了一下 Codeforces原文链接 dsu on tree 简介 我也不清楚dsu是什么的英文缩写... 就像是树上的启发式合 ...
- CF 375D. Tree and Queries【莫队 | dsu on tree】
题意: 一棵树,询问一个子树内出现次数$≥k$的颜色有几种 强制在线见上一道 用莫队不知道比分块高到哪里去了,超好写不用调7倍速度!!! 可以用分块维护出现次数这个权值,实现$O(1)-O(\sqrt ...
- dsu on tree 树上启发式合并 学习笔记
近几天跟着dreagonm大佬学习了\(dsu\ on\ tree\),来总结一下: \(dsu\ on\ tree\),也就是树上启发式合并,是用来处理一类离线的树上询问问题(比如子树内的颜色种数) ...
- UOJ#266. 【清华集训2016】Alice和Bob又在玩游戏 博弈,DSU on Tree,Trie
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ266.html 题解 首先我们可以直接暴力 $O(n^2)$ 用 sg 函数来算答案. 对于一个树就是枚举 ...
- dsu on tree入门
先瞎扯几句 说起来我跟这个算法好像还有很深的渊源呢qwq.当时在学业水平考试的考场上,题目都做完了不会做,于是开始xjb出题.突然我想到这么一个题 看起来好像很可做的样子,然而直到考试完我都只想出来一 ...
- 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree
原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...
- [Codeforces741D]Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths——dsu on tree
题目链接: Codeforces741D 题目大意:给出一棵树,根为$1$,每条边有一个$a-v$的小写字母,求每个点子树中的一条最长的简单路径使得这条路径上的边上的字母重排后是一个回文串. 显然如果 ...
- BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)
BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...
随机推荐
- Finereport和Finebi的区别
1.问题描述 大家现在可能都知道,目前帆软旗下特色产品主要是FineReport和FineBI,但是部分用户可能会有个疑问:FineReport和FineBI到底有什么区别? 2.产品介绍FineRe ...
- ISDBT中CC的处理疑问
一个针对日本的数字电视应用(ISDBT)里字幕处理有一些问题,规范文档庞大又复杂,读起来还觉得语焉不详.接手遗留项目尝试处理字幕显示的问题,边读spec边看代码,先猜测.试图理解既有逻辑,再分析问题产 ...
- memcached 查看所有的key
1. cmd上登录memcache 1 > telnet 127.0.0.1 11211 2. 列出所有keys 1 2 3 4 stats items // 这条是命令 STAT it ...
- 使用 Azure PowerShell 管理 Azure 虚拟网络和 Windows 虚拟机
Azure 虚拟机使用 Azure 网络进行内部和外部网络通信. 本教程介绍了如何在虚拟网络中创建多个虚拟机 (VM),以及如何在虚拟机之间配置网络连接. 你将学习如何执行以下操作: 创建虚拟网络 创 ...
- EOFException异常详解
最近线上的系统被检测出有错误日志,领导让我检查下问题,我就顺便了解了下这个异常. 了解一个类,当然是先去看他的API,EOFException的API如下: 通过这个API,我们可以得出以下信息: 这 ...
- SQL删除多列语句
最近在写SQL过程中发现需要对一张表结构作调整(此处是SQL Server),其中需要删除多列,由于之前都是一条SQL语句删除一列,于是猜想是否可以一条语句同时删除多列,如果可以,怎么写法? 第一次猜 ...
- ngrep命令用法
ngrep 是grep(在文本中搜索字符串的工具)的网络版,他力求更多的grep特征,用于搜寻指定的数据包.正由于安装ngrep需用到libpcap库, 所以支持大量的操作系统和网络协议.能识别TCP ...
- md5sum 和 sha256sum用于 验证软件完整性
md5sum 和 sha256sum 都用来用来校验软件安装包的完整性,本次我们将讲解如何使用两个命令进行软件安装包的校验: sha 是什么? sha 为 安全散列算法(英语:Secur ...
- 匿名访问windows server 2008 R2 文件服务器的共享
匿名访问windows server 2008 R2 文件服务器的共享 匿名访问windows 2008 R2 文件服务器的共享,七步:第一步 取消简单文件共享:第二步 设置需要共享的文件夹every ...
- October 16th 2017 Week 42nd Monday
The more decisions that you are forced to make alone, the more you are aware of your freedom to choo ...