2017省选集训测试赛(二十五)Problem B recollection
@(XSY)[后缀数组, 启发式合并, ST表]
Description
Solution
后缀数组 + 启发式合并 + Sparse Table.
这是第一次写树上后缀数组.
对以每个点为根的子树统计答案, 用一个set来维护子树下每个点节点在的排名, 启发式合并一颗子树的信息和当前节点的信息.
一些边界情况需要注意.
#include <cstdio>
#include <cctype>
#include <cstring>
#include <vector>
#include <algorithm>
#include <set>
#include <cmath>
const int N = 1 << 18, MOD = 998244353, K = 47;
int n;
inline int modPower(int a, int x)
{
int res = 1;
for(; x; a = (long long)a * a % MOD, x >>= 1)
if(x & 1)
res = (long long)res * a % MOD;
return res;
}
namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1;
char c;
while(! isdigit(c = getchar()))
if(c == '-')
sgn *= -1;
while(isdigit(c))
a = a * 10 + c - '0', c = getchar();
return a * sgn;
}
}
struct trieTree
{
int pw[18], hd[N], tp, ltr[N], hsh[N][18];
inline void initialize()
{
memset(hd, -1, sizeof(hd));
tp = 0;
ltr[1] = 0;
for(int i = 0; i < 18; ++ i)
pw[i] = modPower(K, 1 << i);
memset(hsh, 0, sizeof(hsh));
}
struct edge
{
int v, nxt;
}edg[N];
inline void addEdge(int u, int v, int c)
{
edg[tp].v = v, edg[tp].nxt = hd[u];
hd[u] = tp ++;
ltr[v] = c;
}
int dep[N], anc[N][18];
void DFS(int u, int pre)
{
anc[u][0] = pre, hsh[u][0] = ltr[u];
for(int i = 1; i < 18; ++ i)
anc[u][i] = anc[anc[u][i - 1]][i - 1], hsh[u][i] = (hsh[anc[u][i - 1]][i - 1] + (long long)hsh[u][i - 1] * pw[i - 1] % MOD) % MOD;
for(int i = hd[u]; ~ i; i = edg[i].nxt)
dep[edg[i].v] = dep[u] + 1, DFS(edg[i].v, u);
}
int sa[N], rk[N], ht[N];
inline int getLCP(int u, int v)
{
int res = 0;
for(int i = 18 - 1; ~ i; -- i)
if(hsh[u][i] == hsh[v][i])
u = anc[u][i], v = anc[v][i], res += 1 << i;
return res;
}
inline void getSuffixArray()
{
dep[1] = 0;
DFS(1, 1);
static int sum[N];
memset(sum, 0, sizeof(sum));
for(int i = 1; i <= n; ++ i)
++ sum[ltr[i]];
for(int i = 1; i < N; ++ i)
sum[i] += sum[i - 1];
for(int i = 1; i <= n; ++ i)
sa[-- sum[ltr[i]]] = i;
int p = 0;
rk[sa[0]] = p;
for(int i = 1; i < n; ++ i)
rk[sa[i]] = ltr[sa[i]] == ltr[sa[i - 1]] ? p : ++ p;
int lim = p + 1;
for(int len = 0; lim < n; ++ len)
{
static std::vector<int> suc[N];
for(int i = 1; i <= n; ++ i)
suc[i].clear();
for(int i = 0; i < n; ++ i)
if(dep[sa[i]] >= 1 << len)
suc[anc[sa[i]][len]].push_back(sa[i]);
static int tmpSa[N];
int p = 0;
for(int i = 0; i < n; ++ i)
if(dep[sa[i]] < 1 << len)
tmpSa[p ++] = sa[i];
for(int i = 0; i < n; ++ i)
for(std::vector<int>::iterator itr = suc[sa[i]].begin(); itr != suc[sa[i]].end(); ++ itr)
tmpSa[p ++] = *itr;
memset(sum, 0, sizeof(sum));
for(int i = 1; i <= n; ++ i)
++ sum[rk[i]];
for(int i = 1; i < N; ++ i)
sum[i] += sum[i - 1];
for(int i = n - 1; ~ i; -- i)
sa[-- sum[rk[tmpSa[i]]]] = tmpSa[i];
static int tmpRk[N];
memcpy(tmpRk, rk, sizeof(rk));
rk[sa[0]] = p = 0;
for(int i = 1; i < n; ++ i)
{
if(tmpRk[sa[i]] != tmpRk[sa[i - 1]] || tmpRk[anc[sa[i]][len]] != tmpRk[anc[sa[i - 1]][len]])
++ p;
rk[sa[i]] = p;
}
lim = p + 1;
}
ht[0] = 0;
for(int i = 1; i <= n; ++ i)
if(rk[i])
ht[rk[i]] = getLCP(i, sa[rk[i] - 1]);
}
int ST[N << 1][18];
inline void getSparseTable()
{
memset(ST, 127, sizeof(ST));
for(int i = 0; i < n; ++ i)
ST[i][0] = ht[i];
for(int i = 1; i < 18; ++ i)
for(int j = 0; j < n; ++ j)
ST[j][i] = std::min(ST[j][i - 1], ST[j + (1 << i - 1)][i - 1]);
}
inline int getMin(int L, int R)
{
int tmp = log2(R - L + 1);
return std::min(ST[L][tmp], ST[R - (1 << tmp) + 1][tmp]);
}
std::set<int> st[N];
inline std::set<int>::iterator getLast(std::set<int>::iterator p)
{
return -- p;
}
inline std::set<int>::iterator getNext(std::set<int>::iterator p)
{
return ++ p;
}
int DFS1(int u)
{
st[u].insert(rk[u]);
int res = 0;
for(int i = hd[u]; ~ i; i = edg[i].nxt)
{
int v = edg[i].v;
res = std::max(res, DFS1(v));
if(st[u].size() < st[v].size())
std::swap(st[u], st[v]);
for(std::set<int>::iterator itr = st[v].begin(); itr != st[v].end(); ++ itr)
{
st[u].insert(*itr);
std::set<int>::iterator p = st[u].find(*itr);
if(p != st[u].begin())
res = std::max(res, getMin(*getLast(p) + 1, *p) + dep[u]);
if(getNext(p) != st[u].end())
res = std::max(res, getMin(*p + 1, *getNext(p)) + dep[u]);
}
}
return res;
}
inline int getAns()
{
for(int i = 1; i <= n; ++ i)
st[i].clear();
return DFS1(1);
}
}org;
int main()
{
#ifndef ONLINE_JUDGE
freopen("recollection.in", "r", stdin);
freopen("recollection.out", "w", stdout);
#endif
using namespace Zeonfai;
n = getInt();
org.initialize();
for(int i = 2; i <= n; ++ i)
{
int pre = getInt(), c = getInt();
org.addEdge(pre, i, c + 1);
}
org.getSuffixArray();
org.getSparseTable();
printf("%d", org.getAns());
}
2017.8.10 第二次写这一道题
#include <cstdio>
#include <cctype>
#include <vector>
#include <set>
#include <algorithm>
#include <cstring>
namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1;
char c;
while(! isdigit(c = getchar())) if (c == '-') sgn *= -1;
while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
return a * sgn;
}
}
const int N = (int)2e5, LOG = 18, K = 47, MOD = (int)1e9 + 7;
int n, ans = 0;
int pw[LOG];
inline int power(int a, int x)
{
int res = 1;
for(; x; a = (long long)a * a % MOD, x >>= 1) if(x & 1) res = (long long)res * a % MOD;
return res;
}
inline std::set<int>::iterator getPrevious(std::set<int>::iterator p)
{
return -- p;
}
inline std::set<int>::iterator getNext(std::set<int>::iterator p)
{
return ++ p;
}
struct trieTree
{
struct node
{
std::vector<node*> suc, pst[LOG];
node *anc[LOG];
int c, dep, rk, _rk;
int hsh[LOG];
inline node()
{
suc.clear();
for(int i = 0; i < LOG; ++ i) pst[i].clear();
}
}nd[N + 1];
inline void addEdge(int u, int v, int c)
{
nd[v].c = c; nd[u].suc.push_back(nd + v);
}
void DFS(node *u, node *pre)
{
u->dep = pre == NULL ? 0 : pre->dep + 1;
u->anc[0] = pre;
if(u->anc[0] != NULL) u->anc[0]->pst[0].push_back(u);
u->hsh[0] = u->c;
for(int i = 1; i < LOG; ++ i) if(u->anc[i - 1] != NULL)
{
u->anc[i] = u->anc[i - 1]->anc[i - 1];
if(u->anc[i] != NULL) u->anc[i]->pst[i].push_back(u), u->hsh[i] = (u->hsh[i - 1] + (long long)u->anc[i - 1]->hsh[i - 1] * pw[i - 1] % MOD) % MOD;
}
for(auto v : u->suc) DFS(v, u);
}
node *SA[N];
inline void sort()
{
static int sum[N];
memset(sum, 0, sizeof(sum));
for(int i = 1; i <= n; ++ i) ++ sum[nd[i].c];
for(int i = 1; i <= 301; ++ i) sum[i] += sum[i - 1];
for(int i = 1; i <= n; ++ i)
SA[-- sum[nd[i].c]] = nd + i;
int p = 0;
SA[0]->rk = p;
for(int i = 1; i < n; ++ i) SA[i]->rk = SA[i]->c == SA[i - 1]->c ? p : ++ p;
int cnt = p + 1;
for(int i = 0; cnt < n; ++ i)
{
p = 0;
static node *tmpSA[N];
for(int j = 1; j <= n; ++ j) if(nd[j].dep < 1 << i) tmpSA[p ++] = nd + j;
for(int j = 0; j < n; ++ j) for(auto u : SA[j]->pst[i]) tmpSA[p ++] = u;
memset(sum, 0, sizeof(sum));
for(int j = 1; j <= n; ++ j) ++ sum[nd[j].rk];
for(int j = 1; j < cnt; ++ j) sum[j] += sum[j - 1];
for(int j = n - 1; ~ j; -- j) SA[-- sum[tmpSA[j]->rk]] = tmpSA[j];
for(int j = 1; j <= n; ++ j) nd[j]._rk = nd[j].rk;
p = 0;
SA[0]->rk = p;
for(int j = 1; j < n; ++ j)
{
if(SA[j]->_rk != SA[j - 1]->_rk || SA[j - 1]->dep < 1 << i || SA[j - 1]->anc[i]->_rk != SA[j]->anc[i]->_rk) ++ p;
SA[j]->rk = p;
}
cnt = p + 1;
}
}
inline int getLCP(node *u, node *v)
{
int res = 0;
for(int i = LOG - 1; ~ i; -- i) if(u->dep >= 1 << i && v->dep >= 1 << i && u->hsh[i] == v->hsh[i])
res += 1 << i, u = u->anc[i], v =v->anc[i];
return res;
}
inline void merge(int dep, std::set<int> &a, std::set<int> &b)
{
if(a.size() < b.size()) std::swap(a, b);
for(std::set<int>::iterator p = b.begin(); p != b.end(); ++ p)
{
a.insert(*p);
std::set<int>::iterator tmp = a.find(*p);
if(tmp != a.begin()) ans = std::max(ans, dep + getLCP(SA[*getPrevious(tmp)], SA[*p]));
if(getNext(tmp) != a.end()) ans = std::max(ans, dep + getLCP(SA[*getNext(tmp)], SA[*p]));
}
b.clear();
}
std::set<int> getAnswer(node *u)
{
std::set<int> st; st.clear(); st.insert(u->rk);
for(auto v : u->suc)
{
std::set<int> tmp = getAnswer(v);
merge(u->dep, tmp, st);
}
return st;
}
}T;
int main()
{
#ifndef ONLINE_JUDGE
freopen("recollection.in", "r", stdin);
freopen("recollection.out", "w", stdout);
#endif
using namespace Zeonfai;
for(int i = 0; i < LOG; ++ i) pw[i] = power(K, 1 << i);
n = getInt();
for(int i = 2; i <= n; ++ i)
{
int pre = getInt(), c = getInt() + 1;
T.addEdge(pre, i, c);
}
T.DFS(T.nd + 1, NULL);
T.sort();
T.getAnswer(T.nd + 1);
printf("%d\n", ans);
}
2017省选集训测试赛(二十五)Problem B recollection的更多相关文章
- 2016北京集训测试赛(十)Problem A: azelso
Solution 我们把遇到一个旗子或者是遇到一个敌人称为一个事件. 这一题思路的巧妙之处在于我们要用\(f[i]\)表示从\(i\)这个事件一直走到终点这段路程中, \(i\)到\(i + 1\)这 ...
- 【2016北京集训测试赛(十)】 Azelso (期望DP)
Time Limit: 1000 ms Memory Limit: 256 MB Description 题解 状态表示: 这题的状态表示有点难想...... 设$f_i$表示第$i$个事件经过之 ...
- 【2016北京集训测试赛(十六)】 River (最大流)
Description Special Judge Hint 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. 题解 题目大意:给定两组点,每组有$n$个点,有若干条跨组 ...
- 2016集训测试赛(十九)Problem C: 无聊的字符串
Solution 傻X题 我的方法是建立后缀后缀树, 然后在DFS序列上直接二分即可. 关键在于如何得到后缀树上每个字符对应的字节点: 我们要在后缀自动机上记录每个点在后缀树上对应的字母. 考虑如何实 ...
- 2016集训测试赛(十九)Problem A: 24点大师
Solution 这到题目有意思. 首先题目描述给我们提供了一种非常管用的模型. 按照题目的方法, 我们可以轻松用暴力解决20+的问题; 关键在于如何构造更大的情况: 我们发现 \[ [(n + n) ...
- 2016集训测试赛(十八)Problem C: 集串雷 既分数规划学习笔记
Solution 分数规划经典题. 话说我怎么老是忘记分数规划怎么做呀... 所以这里就大概写一下分数规划咯: 分数规划解决的是这样一类问题: 有\(a_1, a_2 ... a_n\)和\(b_1, ...
- 2016北京集训测试赛(十六)Problem C: ball
Solution 这是一道好题. 考虑球体的体积是怎么计算的: 我们令\(f_k(r)\)表示\(x\)维单位球的体积, 则 \[ f_k(1) = \int_{-1}^1 f_{k - 1}(\sq ...
- 2016北京集训测试赛(十六)Problem B: river
Solution 这题实际上并不是构造题, 而是一道网络流. 我们考虑题目要求的一条路径应该是什么样子的: 它是一个环, 并且满足每个点有且仅有一条出边, 一条入边, 同时这两条边的权值还必须不一样. ...
- 2016北京集训测试赛(十六)Problem A: 任务安排
Solution 这道题告诉我们, 不能看着数据范围来推测正解的时间复杂度. 事实证明, 只要常数足够小, \(5 \times 10^6\)也是可以跑\(O(n \log n)\)算法的!!! 这道 ...
随机推荐
- leetcode 【Search a 2D Matrix 】python 实现
题目: Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the f ...
- 2018CCPC网络赛
A - Buy and Resell HDU - 6438 The Power Cube is used as a stash of Exotic Power. There are nn cities ...
- 在数组中寻找出现次数大于N/K的数
给定一个int[]数组,给定一个整数k,打印所有出现次数大于N/k的数,没有的话,给出提示信息. === 核心思想:一次在数组中删除K个不同的数,不停的删除,直到剩下的数的种类不足K就停止删除,那么如 ...
- [已解决]Argument list too long如何处理?
Argument list too long 本质是需要处理的长度超过系统的长度,因此无法执行相关命令. 经过搜索发现了两种方法,思想都是将参数切分成小的段落进行执行. 法一:通过xargs传递参数 ...
- Redhat/CentOS安装vsftp软件
1.更新yum源 首先需要更新系统的yum源,便捷工具下载地址:http://help.aliyun.com/manual?spm=0.0.0.0.zJ3dBU&helpId=1692 2.安 ...
- AngularJs MVC 详解
为什么在前端也需要MVC 1.代码规模越来越大,切分职责是大势所趋 2.为了复用 3.为了后期维护方便 MVC的目的是为了模块化和复用 前端实现MVC的困难 1.操作DOM必须等整个页面加载完 2.多 ...
- 习题:Wormhole(思路题)
tyvj1763 描述 一维的世界就是一个数轴.这个世界的狭小我们几乎无法想象.在这个数轴上,有N个点.从左到右依次标记为点1到N.第i个点的坐标为Xi.经过漫长时间的物理变化和化学变化,这个一维世界 ...
- php处理ajax
首先安装wamp,若安装过mysql则终止进程防止冲突,可以访问localhost说明成功.在www目录下新建项目,使用localhost访问. php: <?php //3.获取ajax传过来 ...
- bzoj 1367 - sequence
Description 给定一个序列\(t_1,t_2,\cdots,t_n\),求一个递增序列\(z_1<z_2<...<z_n\), 使得 \(R=|t_1−z_1|+|t_2− ...
- 《挑战程序设计竞赛》P196 铺砖问题
题意:给定n*m格子,每个格子被染成了黑色或者白色,现在要用1*2的砖块覆盖这些格子,块与块不得重叠,且覆盖所有的白色格子,但不覆盖任意一个黑色格子,求一共有多少种覆盖方法. 思路:书上给的思路太巧妙 ...