Description

对于一棵有根树,定义一个点u的k-子树为u的子树中距离u不超过k的部分。
注意,假如u的子树中不存在距离u为k的点,则u的k-子树是不存在的。
定义两棵子树是相同的,当且仅当不考虑点的标号时,他们的形态是
相同的(儿子的顺序也需要考虑)。给定一棵n个点,点的标号在[1,n],
以1为根的有根树。问最大的k,使得存在两个点u !=v,满足u的k-子树与v的k-子树相同。

Input

第一行输入一个正整数n。
接下来读入n个部分,第i个部分描述点i的儿子,且以顺序给出。
每个部分首先读入一个整数x,代表儿子个数。
接下来x个整数,代表从左到右儿子的标号
n ≤ 100000,保证给出的树是合法的

Output

输出一个整数k,代表最大的合法的k
已知每个点的a-子树和b-子树的hash,可以推出每个点的(a+b)-子树的hash
对答案倍增,hash判定
#include<cstdio>
#include<cstring>
#define Fe(i,l,r) for(int i=l;i<=r;++i)
typedef unsigned long long u64;
const int N=,P=;
void maxs(int&a,int b){if(a<b)a=b;}
u64 H(u64 x){return (x^x>>^x<<)+;}
char buf[],*ptr=buf+;
int G(){
if(ptr-buf==)fread(ptr=buf,,,stdin);
return *ptr++;
}
int _(){
int x=;
if(ptr-buf<){
while(*ptr<)++ptr;
while(*ptr>)x=x*+*ptr++-;
}else{
int c=G();
while(c<)c=G();
while(c>)x=x*+c-,c=G();
}
return x;
}
int n,ans=;
int mem[N],*mp=mem,*e[N],ep[N],fa[][N],fas[N],id[N],_fa[N],_son[N];
int q[N],ql=,qr=,dep[N],md[N];
u64 h[][N],h2[N],_h[N];
u64 hx[P];
int ht[P],tk=;
bool ins(u64 x){
int w=(unsigned(x)^unsigned(x>>))%P;
while(ht[w]==tk){
if(hx[w]==x)return ;
if((w+=)>=P)w-=P;
}
hx[w]=x;ht[w]=tk;
return ;
}
template<class T>
void cpy(T*a,T*b){memcpy(a+,b+,sizeof(T)*n);}
void getson(){
memset(_son+,,sizeof(int)*n);
Fe(t,,qr){
int w=q[t],f=fas[w];
if(!_son[f])_son[f]=t;
}
}
void cal(int _i){
cpy(_h,h[_i]);
cpy(_fa,fa[_i]);
for(int i=_i-;i>=;--i){
++tk;
cpy(h2,_h);
getson();
Fe(t,,qr){
int w=q[t],f=_fa[w];
if(f)h2[f]=h2[f]*+h[i][w]+(id[fa[][w]]-_son[f]);
}
bool is=;
int mn=ans+(<<i);
Fe(w,,n)if(md[w]+>=mn&&ins(h2[w])){
is=;
break;
}
if(is){
ans=mn;
Fe(w,,n){
_h[w]=H(h2[w]);
_fa[w]=fa[i][_fa[w]];
fas[w]=fa[i][fas[w]];
}
}
}
}
void cal(){
Fe(w,,n)h[][w]=;
for(int i=;i<;++i){
++tk;
cpy(h2,h[i]);
getson();
Fe(t,,qr){
int w=q[t],f=fa[i][w];
if(f)h2[f]=h2[f]*+h[i][w]+(id[fa[][w]]-_son[f]);
}
bool is=;
int mn=ans+(<<i);
Fe(w,,n)if(md[w]+>=mn&&ins(h2[w])){
is=;
break;
}
if(is){
ans=mn;
Fe(w,,n){
h[i+][w]=H(h2[w]);
fa[i+][w]=fa[i][fa[i][w]];
fas[w]=fa[i][fas[w]];
}
}else return cal(i);
}
}
int main(){
n=_();
for(int i=;i<=n;++i){
fas[i]=i;
e[i]=mp;
mp+=ep[i]=_();
for(int j=;j<ep[i];++j)fa[][e[i][j]=_()]=i;
}
for(q[++qr]=;fa[][q[]];++q[]);
while(ql!=qr){
int w=q[++ql];
id[w]=ql;
for(int*l=e[w],*r=l+ep[w];l!=r;++l)dep[q[++qr]=*l]=dep[w]+;
}
for(int i=qr;i;--i){
int w=q[i];
maxs(md[fa[][w]],md[w]+);
}
cal();
printf("%d\n",ans-);
return ;
}

bzoj4928: 第二题的更多相关文章

  1. 【BZOJ4928】第二题 树hash+倍增

    [BZOJ4928]第二题 Description 对于一棵有根树,定义一个点u的k-子树为u的子树中距离u不超过k的部分. 注意,假如u的子树中不存在距离u为k的点,则u的k-子树是不存在的. 定义 ...

  2. 05:统计单词数【NOIP2011复赛普及组第二题】

    05:统计单词数 总时间限制:  1000ms 内存限制:  65536kB 描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次 ...

  3. 常见面试第二题之什么是Context

    今天的面试题,也就是我们常见面试题系列的第二题,我们来讲一讲android中的context.我相信大家android开发者一定对于这个context非常熟悉,肯定都有使用过,肯定没有没使用过的.但是 ...

  4. 《学习OpenCV》练习题第五章第二题abc

    代码: #include <stdio.h> #include <opencv/highgui.h> #include <opencv/cv.h> #include ...

  5. 《学习OpenCV》练习题第四章第二题

    #include <highgui.h> #include <cv.h> #pragma comment (lib,"opencv_calib3d231d.lib&q ...

  6. CSDN挑战编程——《金色十月线上编程比赛第二题:解密》

    金色十月线上编程比赛第二题:解密 题目详情: 小强是一名学生, 同一时候他也是一个黑客. 考试结束后不久.他吃惊的发现自己的高等数学科目竟然挂了,于是他果断入侵了学校教务部站点. 在入侵的过程中.他发 ...

  7. NOIP2005-普及组复赛-第二题-校门外的树

    题目描述 Description 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0 ...

  8. 【gdoi2018 day2】第二题 滑稽子图(subgraph)(性质DP+多项式)

    题目大意 [gdoi2018 day2]第二题 滑稽子图(subgraph) 给你一颗树\(T\),以及一个常数\(K\),对于\(T\)的点集\(V\)的子集\(S\). 定义\(f(S)\)为点集 ...

  9. 【LOJ#6066】「2017 山东一轮集训 Day3」第二题(哈希,二分)

    [LOJ#6066]「2017 山东一轮集训 Day3」第二题(哈希,二分) 题面 LOJ 题解 要哈希是很显然的,那么就考虑哈希什么... 要找一个东西可以表示一棵树,所以我们找到了括号序列. 那么 ...

随机推荐

  1. poj2895

    题解: splay,维护当前第k大 并查集维护当前集合 合并x,y时,del(num[x]),del(num[y]),insert(num[x]+num[y]) 代码: #include<cst ...

  2. git push时候总提示输入账号密码,如何免除设置?

    1. 打开.ssh所在目录 home,即C:\Users\Administrator2. 在home中,进入git bash命令终端,创建.git-credentials文件,编辑 touch .gi ...

  3. Nutch相关视频教程3

    参考: http://www.cnblogs.com/huligong1234/p/3515214.html

  4. 2.4 C++成员选择符

    参考:http://www.weixueyuan.net/view/6336.html 总结: 访问可以通过成员选择符“.”或指针操作符“->”来完成. 通过上一节的学习我们看到:通过对象可以访 ...

  5. 【数据库】MFC ODBC(三)

    4.SQL查询 记录集的建立实际上是一个查询过程,SQL的SELECT语句用来查询数据源.在建立记录集时,CRecordset会根据一些参数构造一个SELECT语句来查询数据源,并用查询的结果创建记录 ...

  6. vue-compile概述

    来源 刘涛 Vue的核心可以分为三个大块:数据处理和双向绑定.模板编译.虚拟dom. 前面我们对第一部分的主要内容双向绑定做了一个分析讲解,接下来我们说一说模板编译. 这一部分的内容比较多,也比较复杂 ...

  7. Python_常用的正则表达式处理函数

    正则表达式就是用查找字符串的,它能查找规则比较复杂的字符串反斜杠:正则表达式里面用"\"作为转义字符. s='<a class="h3" href=&qu ...

  8. webstrom vue配置eslint

    (得出结论,还是得从官方文档中找,哇!!) 1.安装eslint插件,可以从search in repositories中获得,或者:http://plugins.jetbrains.com/plug ...

  9. webpack 添加 jquery 插件

    webpack.base.config.js 加入以下配置: , plugins: [ new webpack.ProvidePlugin({ jQuery: 'jquery', $: 'jquery ...

  10. 在本地设置 http-proxy 代理 (前后端分离)

    1. 利用package.json 安装nodejs,创建package.json文件:内容如下 "dependencies": { "http-proxy": ...