【LOJ#6066】「2017 山东一轮集训 Day3」第二题(哈希,二分)
【LOJ#6066】「2017 山东一轮集训 Day3」第二题(哈希,二分)
题面
题解
要哈希是很显然的,那么就考虑哈希什么。。。
要找一个东西可以表示一棵树,所以我们找到了括号序列。
那么二分一个答案\(d\),把所有点挂到\(d+1\)次祖先上去,那么\(d+1\)次祖先的哈希值就是它原本的括号序列挖去了若干段,直接暴力哈希拼接起来就好了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define MAX 100100
#define ull unsigned long long
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n;
struct Line{int v,next;}e[MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int p[20][MAX],lg[MAX],dfn[MAX],low[MAX],dep[MAX];
int a[MAX<<1],tot,maxdep;
ull pw[MAX<<1],H[MAX<<1];
const ull base=233;
void dfs(int u,int ff)
{
p[0][u]=ff;a[++tot]=1;dfn[u]=tot;dep[u]=dep[ff]+1;
for(int j=1;j<=lg[n];++j)p[j][u]=p[j-1][p[j-1][u]];
for(int i=h[u];i;i=e[i].next)dfs(e[i].v,u);
a[++tot]=0;low[u]=tot;
}
int parent(int x,int k)
{
for(int i=lg[n];~i;--i)
if(k&(1<<i))x=p[i][x];
return x;
}
ull hs(int l,int r){return H[r]-H[l-1]*pw[r-l+1];}
vector<int> son[MAX];
bool cmp(int a,int b){return dfn[a]<dfn[b];}
set<ull> S;
bool vis[MAX];
bool check(int d)
{
for(int i=0;i<=n;++i)vis[i]=false,son[i].clear();
for(int i=1;i<=n;++i)
{
int ff=parent(i,d);vis[ff]=true;
son[p[0][ff]].push_back(i);
}
S.clear();
for(int i=1;i<=n;++i)
{
int l=son[i].size();if(!vis[i])continue;
sort(son[i].begin(),son[i].end(),cmp);
int L=dfn[i];ull H=0;
for(int j=0;j<l;++j)
H=H*pw[dfn[son[i][j]]-L]+hs(L,dfn[son[i][j]]-1),L=low[son[i][j]]+1;
H=H*pw[low[i]-L+1]+hs(L,low[i]);
if(S.find(H)!=S.end())return true;
S.insert(H);
}
return false;
}
int main()
{
n=read();pw[0]=1;
for(int i=1;i<=n;++i)
{
int x=read();
for(int j=1;j<=x;++j)Add(i,read());
}
for(int i=2;i<=n;++i)lg[i]=lg[i>>1]+1;
for(int i=1;i<=n+n;++i)pw[i]=pw[i-1]*base;
dfs(1,0);
for(int i=1;i<=tot;++i)H[i]=H[i-1]*base+a[i];
for(int i=1;i<=n;++i)maxdep=max(maxdep,dep[i]);
int l=1,r=maxdep,ret=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))l=mid+1,ret=mid;
else r=mid-1;
}
printf("%d\n",ret);
return 0;
}
【LOJ#6066】「2017 山东一轮集训 Day3」第二题(哈希,二分)的更多相关文章
- [LOJ#6066]. 「2017 山东一轮集训 Day3」第二题[二分+括号序列+hash]
题意 题目链接 分析 首先二分,假设二分的答案为 \(mid\),然后考虑利用括号序列来表示树的形态. 点 \(u\) 的 \(k-\) 子树的括号序列表示实际上是刨去了 \(u\) 子树内若干个与 ...
- LOJ6066:「2017 山东一轮集训 Day3」第二题
传送门 二分答案 \(k\),考虑如何 \(hash\) 使得做起来方便 把每个点挂在 \(k+1\) 级祖先上,考虑在祖先上删除 这道题巧妙在于其可以对于 \(dfs\) 序/括号序列 \(hash ...
- Loj #6069. 「2017 山东一轮集训 Day4」塔
Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ...
- Loj #6073.「2017 山东一轮集训 Day5」距离
Loj #6073.「2017 山东一轮集训 Day5」距离 Description 给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\) ...
- Loj 6068. 「2017 山东一轮集训 Day4」棋盘
Loj 6068. 「2017 山东一轮集训 Day4」棋盘 题目描述 给定一个 $ n \times n $ 的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置 $ (x, y),(u, ...
- LOJ #6074. 「2017 山东一轮集训 Day6」子序列
#6074. 「2017 山东一轮集训 Day6」子序列 链接 分析: 首先设f[i][j]为到第i个点,结尾字符是j的方案数,这个j一定是从i往前走,第一个出现的j,因为这个j可以代替掉前面所有j. ...
- loj #6077. 「2017 山东一轮集训 Day7」逆序对
#6077. 「2017 山东一轮集训 Day7」逆序对 题目描述 给定 n,k n, kn,k,请求出长度为 n nn 的逆序对数恰好为 k kk 的排列的个数.答案对 109+7 10 ^ 9 ...
- LOJ #6119. 「2017 山东二轮集训 Day7」国王
Description 在某个神奇的大陆上,有一个国家,这片大陆的所有城市间的道路网可以看做是一棵树,每个城市要么是工业城市,要么是农业城市,这个国家的人认为一条路径是 exciting 的,当且仅当 ...
- loj#6073. 「2017 山东一轮集训 Day5」距离(树链剖分 主席树)
题意 题目链接 Sol 首先对询问差分一下,我们就只需要统计\(u, v, lca(u, v), fa[lca(u, v)]\)到根的路径的贡献. 再把每个点与\(k\)的lca的距离差分一下,则只需 ...
随机推荐
- Laravel Providers——服务提供者的注册与启动源码解析
本文 GitBook 地址: https://www.gitbook.com/book/leoyang90/laravel-source-analysishttps://learnku.com/a ...
- spring IOC源码分析(ApplicationContext)
在上一篇文章中,我们以BeanFactory这条主线进行IOC的源码解析的,这里,将以ApplicationContext这条线进行分析.先看使用方法: @Test public void testA ...
- hadoop的缺点
Hadoop的限制 Hadoop只能执行批量处理,并且只以顺序方式访问数据.这意味着必须搜索整个数据集,即使是最简单的搜索工作.
- Linux基础学习(13)--Linux系统管理
第十三章——Linux系统管理 一.进程管理 1.进程查看: (1)进程简介:进程是正在执行的一个程序或命令,每一个进程都是一个运行的实体,都有自己的地址空间,并占用一定的系统资源. (2)进程管理的 ...
- 无法将从VSS中的解决方案添加到TFS的源代码管理器中
VSS是一种非常有用的项目文件管理工具,百度百科的解释是:VSS 的全称为 Visual Source Safe .作为 Microsoft Visual Studio 的一名成员,它主要任务就是负责 ...
- Java多线程系列——原子类的实现(CAS算法)
1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...
- 集合之LinkedList(含JDK1.8源码分析)
一.前言 LinkedList是基于链表实现的,所以先讲解一下什么是链表.链表原先是C/C++的概念,是一种线性的存储结构,意思是将要存储的数据存在一个存储单元里面,这个存储单元里面除了存放有待存储的 ...
- python设计模式第八天【装饰器模式】
1.定义 使用包装的释放扩展类的功能,但是不使用继承 2.使用场景 3.代码实现 #!/usr/bin/env python #! _*_ coding:UTF-8 _*_ def MyDecorat ...
- 在delphi中生成GUID/自动获取临时表名......
什么是 GUID ? 全球唯一标识符 (GUID) 是一个字母数字标识符,用于指示产品的唯一性安装.在许多流行软件应用程序(例如 Web 浏览器和媒体播放器)中,都使用 GUID. GUID 的格式为 ...
- SOJ 1685:chopsticks(dp)
题目链接 说实话挺喜欢soj的界面,简简单单,没有多余的东西hhh(但是简单到连内存限制,时间限制都看不到了. 题意是有个“奇葩”的主人公,吃饭要用三根筷子.两根短的一根长的. 现在给你n根筷子,要在 ...