【BZOJ4928】第二题

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

Sample Input

8
1
2
2
3 4
0
1
5
2
6 7
0
1
8
0

Sample Output

3

题解:依旧是集训原题。

由于答案是可二分的,考虑倍增。我们用f[i][x]表示x的-(1<<i)子树的hash值。那么,如果我们已经知道了所有点的-a子树的hash值和-b子树的hash值,如何求出-(a+b)的hash值呢?这就需要我们有一种hash的方法,即保证hash的正确性也要便于我们合并。

然后看标程看到好多种hash的方法,这里只说一种比较简单的。

特别地,我们令f[0][x]的hash值为x的儿子数量(你可以想象,如果一棵树的DFS序确定了,DFS序上每个点的权值就是它的儿子数量,那么这个DFS序就能唯一的表示一棵树)。然后在合并-a和-b的时候如何处理呢?我们按照DFS序遍历x的所有到x的距离为a的子孙,然后设它们的-b子树的hash值分别为b1,b2...bm,那么我们相当于得到一个序列{a,b1,b2...bm},我们将这个序列hash一下(hash=a*basem+b1*basem-1+...bm*1)。最后,我们将所有点的hash值排个序,反离散化一下,得到的排名就是x的-(a+b)子树的hash值。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
const int maxn=100010;
int n,mx,ans,len,now;
const ull bas=2543323;
ull hs[20][maxn],f[maxn],nf[maxn],pv[maxn];
vector <int> ch[maxn];
int dep[maxn],p[maxn],st[maxn],md[maxn],vis[maxn];
int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void dfs(int x,ull *a,ull *b,ull *c)
{
int i,y;
if(x==1) p[0]=st[0]=0,dep[1]=1;
st[dep[x]]=x,md[x]=dep[x],a[x]=b[x];
if(dep[x]>len) (a[st[dep[x]-len]]*=bas)+=c[x];
for(i=0;i<ch[x].size();i++) y=ch[x][i],dep[y]=dep[x]+1,dfs(y,a,b,c),md[x]=max(md[x],md[y]);
st[0]--;
}
bool cmp(int a,int b)
{
return pv[a]<pv[b];
}
void merge(ull *a,ull *b,ull *c,int l)
{
len=l;
dfs(1,a,b,c);
int i,j;
for(i=1;i<=n;i++) p[i]=i,pv[i]=a[i];
sort(p+1,p+n+1,cmp);
for(i=1,j=0;i<=n;i++)
{
if(pv[p[i]]>pv[p[i-1]]) j++;
a[p[i]]=j;
}
}
int check(ull *a,ull *b,ull *c,int l)
{
merge(a,b,c,ans);
now++;
for(int i=1;i<=n;i++)
{
if(md[i]-dep[i]>=l)
{
if(vis[a[i]]==now) return 1;
vis[a[i]]=now;
}
}
return 0;
}
int main()
{
n=rd();
int i,j,a;
for(i=1;i<=n;i++)
{
a=rd(),hs[0][i]=a;
for(j=1;j<=a;j++) ch[i].push_back(rd());
}
for(i=1;i<=16;i++) merge(hs[i],hs[i-1],hs[i-1],1<<i-1);
for(i=16;i>=0;i--)
{
if(check(nf,f,hs[i],ans+(1<<i)))
{
ans+=(1<<i);
memcpy(f,nf,sizeof(nf));
}
}
printf("%d",ans);
return 0;
}

【BZOJ4928】第二题 树hash+倍增的更多相关文章

  1. bzoj4928: 第二题

    Description 对于一棵有根树,定义一个点u的k-子树为u的子树中距离u不超过k的部分. 注意,假如u的子树中不存在距离u为k的点,则u的k-子树是不存在的. 定义两棵子树是相同的,当且仅当不 ...

  2. LOJ.6066.[2017山东一轮集训Day3]第二题(树哈希 二分)

    LOJ 被一件不愉快的小事浪费了一个小时= =. 表示自己(OI方面的)智商没救了=-= 比较显然 二分+树哈希.考虑对树的括号序列进行哈希. 那么每个点的\(k\)子树的括号序列,就是一段区间去掉距 ...

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

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

  4. 【codevs2370】小机房的树 LCA 倍增

    2370 小机房的树  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0 ...

  5. Bzoj3197/洛谷3296 [SDOI2013]刺客信条assassin(树的重心+树Hash+树形DP+KM)

    题面 Bzoj 洛谷 题解 (除了代码均摘自喻队的博客,可是他退役了) 首先固定一棵树,枚举另一棵树,显然另一棵树只有与这棵树同构才有可能产生贡献 如果固定的树以重心为根,那么另一棵树最多就只有重心为 ...

  6. 【CSP模拟赛】仔细的检查(树的重心&树hash)

    题目描述 nodgd家里种了一棵树,有一天nodgd比较无聊,就把这棵树画在了一张纸上.另一天nodgd更无聊,就又画了一张.  这时nodgd发现,两次画的顺序是不一样的,这就导致了原本的某一个节点 ...

  7. hdu 1556:Color the ball(第二类树状数组 —— 区间更新,点求和)

    Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  8. BZOJ_2124_等差子序列_线段树+Hash

    BZOJ_2124_等差子序列_线段树+Hash Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pL ...

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

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

随机推荐

  1. 转:windows 查找pid并kill进程

    找出占用1099端口的进程,进入windows命令,查看什么进程占用了1099端口 使用命令:netstat -aon|findstr 1099 找出占用1099端口的进程,如下图所示:

  2. vscode - 添加背景图片

    首先,Ctrl+Shift+P安装backround , 而后重启vscode会有默认的背景图片 修改背景图,可自定义三张 具体请看gif图 最开始时,发现png根本不是全透明,用ps处理了一下(下列 ...

  3. 创建你的第一个ionic+cordova应用(1)

    前面我们安装了前端的神器webstorm11,体验到了强大的开发体验,接着我们来安装ionic 必备: Node.js (npm安装工具) 百度下载 官网下载  注:如果官网新版不能安装请用百度下载0 ...

  4. hdu - 4974 - A simple water problem(贪心 + 反证)

    题意:N个队(N <= 100000),每一个队有个总分ai(ai <= 1000000),每场比赛比赛两方最多各可获得1分,问最少经过了多少场比赛. 题目链接:http://acm.hd ...

  5. poj 1719Shooting Contest

    //本题大意是对于一个r*c的矩阵,每一列有两个是白色的 //如今选c个位置,要求每一行至少有一个白色的方格被选上 //每一列仅仅能选一个 //用二分匹配求出最大匹配,假设最大匹配等于r,则满足 // ...

  6. react native使用 mobx , can't find variable:Symbol

    原因是因为 mobx的版本用的最新版本..用到了 Symbol部分es6的api特性. 解决问题办法 1. 把mobx降版本到 4.3.1 . mobx-react降版本到 5.1.0 即可. 或者 ...

  7. 实战Jquery(一)--username校验

    歇息了好几天,最终又開始学习了.jQuery? JQuery is designed to change the way that you write JavaScript. The focus of ...

  8. Git命令学习之旅——日志和穿梭版本号

    在总结了git命令的基础之后,接下来我们看一下基础的一些进阶内容:删除撤销命令.日志查看命令等 既然有加入文件的功能,那么相相应的肯定有移除文件的功能,命令例如以下:git rm [文件名称] 在输入 ...

  9. Oracle 日期总结

    一.带星期格式 .SELECT to_char(to_date('2014-12-12','yyyy-mm-dd'),'MM-DD (DAY)') FROM DUAL .SELECT to_char( ...

  10. Android应用程序开发以及背后的设计思想深度剖析

    1 http://www.uml.org.cn/mobiledev/201211063.asp 2 ...