luogu P4482 [BJWC2018] Border 的四种求法 - 后缀数组
照着金策讲稿做。
Code
/**
* luogu
* Problem#P4482
* Accepted
* Time: 8264ms
* Memory: 37924k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; template <typename T>
void pfill(T* pst, const T* ped, T val) {
for ( ; pst != ped; *(pst++) = val);
} const int N = 2e5 + ;
const int bzmax = ;
const signed int inf = (signed) (~0u >> ); typedef class SparseTable {
public:
int n;
int *ar;
int log2[N];
int f[N][bzmax]; SparseTable() { } void init(int n, int* ar) {
this->n = n;
this->ar = ar;
log2[] = ;
for (int i = ; i <= n; i++)
log2[i] = log2[i >> ] + ;
for (int i = ; i < n; i++)
f[i][] = ar[i];
for (int j = ; j < bzmax; j++)
for (int i = ; i + ( << j) - < n; i++)
f[i][j] = min(f[i][j - ], f[i + ( << (j - ))][j - ]);
} int query(int l, int r) {
int d = log2[r - l + ];
return min(f[l][d], f[r - ( << d) + ][d]);
}
} SparseTable; typedef class Pair3 {
public:
int x, y, id; Pair3() { }
Pair3(int x, int y, int id):x(x), y(y), id(id) { }
} Pair3; typedef class SuffixArray {
protected:
Pair3 T1[N], T2[N];
int cnt[N]; public:
int n;
char *str;
int sa[N], rk[N], hei[N];
SparseTable st; void set(int n, char* str) {
this->n = n;
this->str = str;
memset(sa, , sizeof(sa));
memset(rk, , sizeof(rk));
memset(hei, , sizeof(hei));
} void radix_sort(Pair3* x, Pair3* y) {
int m = max(n, );
memset(cnt, , sizeof(int) * m);
for (int i = ; i < n; i++)
cnt[x[i].y]++;
for (int i = ; i < m; i++)
cnt[i] += cnt[i - ];
for (int i = ; i < n; i++)
y[--cnt[x[i].y]] = x[i]; memset(cnt, , sizeof(int) * m);
for (int i = ; i < n; i++)
cnt[y[i].x]++;
for (int i = ; i < m; i++)
cnt[i] += cnt[i - ];
for (int i = n - ; ~i; i--)
x[--cnt[y[i].x]] = y[i];
} void build() {
for (int i = ; i < n; i++)
rk[i] = str[i];
for (int k = ; k <= n; k <<= ) {
for (int i = ; i + k < n; i++)
T1[i] = Pair3(rk[i], rk[i + k], i);
for (int i = n - k; i < n; i++)
T1[i] = Pair3(rk[i], , i);
radix_sort(T1, T2);
int diff = ;
rk[T1[].id] = ;
for (int i = ; i < n; i++)
rk[T1[i].id] = (T1[i].x == T1[i - ].x && T1[i].y == T1[i - ].y) ? (diff) : (++diff);
if (diff == n)
break;
}
for (int i = ; i < n; i++)
sa[--rk[i]] = i;
} void get_height() {
for (int i = , j, k = ; i < n; i++, (k) ? (k--) : ()) {
if (rk[i]) {
j = sa[rk[i] - ];
while (i + k < n && j + k < n && str[i + k] == str[j + k]) k++;
hei[rk[i]] = k;
}
}
} void init_st() {
st.init(n, hei);
} int lcp(int x1, int x2) {
if (x1 == x2)
return n - x1 + ;
x1 = rk[x1], x2 = rk[x2];
if (x1 > x2)
swap(x1, x2);
return st.query(x1 + , x2);
} int compare(int l1, int r1, int l2, int r2) {
int len_lcp = lcp(l1, l2);
int len1 = r1 - l1 + , len2= r2 - l2 + ;
if (len_lcp >= len1 && len_lcp >= len2)
return ;
if (len_lcp < len1 && len_lcp < len2)
return (str[l1 + len_lcp] < str[l2 + len_lcp]) ? (-) : ();
return (len_lcp >= len1) ? (-) : ();
} int query(int u, int v) { // u, v -> sa
if (u == v)
return n - sa[u];
return st.query(u + , v);
} const int& operator [] (int p) {
return sa[p];
} const int& operator () (int p) {
return hei[p];
}
} SuffixArray; namespace IPM { // Internal Pattern Matching typedef class MatchingData {
public:
int a0, a1;
int amount; MatchingData() : amount() { }
explicit MatchingData(int a0) : a0(a0), a1(a0), amount() { }
MatchingData(int a0, int a1) : a0(a0), a1(a1), amount( + (a0 != a1)) { }
MatchingData(int a0, int a1, int amount) : a0(a0), a1(a1), amount(amount) { }
MatchingData(int* a, int amount) : amount(amount) {
if (amount == )
return;
if (amount == )
a0 = a1 = a[];
else if (amount >= ) {
a0 = a[], a1 = a[];
int d = a1 - a0;
for (int i = ; i < amount; i++)
if (a[i] - a[i - ] != d)
assert(false);
}
} boolean included(int x) {
if (!amount)
return false;
boolean aflag = (x == a0 || x == a1);
if (amount <= || aflag)
return aflag;
x -= a0;
int d = a1 - a0;
return (!(x % d) && (x / d >= && x / d < amount));
} int indexOf(int x) {
if (!included(x))
return -;
return (x - a0) / (a1 - a0);
} int last() {
return value(amount - );
} int value(int n) {
return a0 + (a1 - a0) * n;
} int dif() {
return a1 - a0;
} MatchingData operator - () {
return MatchingData(-a0, -a1, amount);
} MatchingData operator + (int d) {
return MatchingData(a0 + d, a1 + d, amount);
} MatchingData operator - (int d) {
return MatchingData(a0 - d, a1 - d, amount);
} MatchingData operator ~ () {
if (amount <= )
return *this;
int _a0 = value(amount - );
int _a1 = value(amount - );
return MatchingData(_a0, _a1, amount);
} MatchingData operator & (MatchingData b) {
static int tmp[];
if (!amount || !b.amount)
return MatchingData();
if (amount < ) {
int tp = ;
for (int i = , x = a0, d = a1 - a0; i < amount; i++, x += d) {
if (b.included(x)) {
tmp[tp++] = x;
}
}
return MatchingData(tmp, tp);
}
if (b.amount < ) {
int tp = ;
for (int i = , x = b.a0, d = b.a1 - b.a0; i < b.amount; i++, x += d) {
if (included(x)) {
tmp[tp++] = x;
}
}
return MatchingData(tmp, tp);
}
int d = a1 - a0;
assert(d == b.a1 - b.a0);
int l = indexOf(b.a0), r = l + b.amount;
if (l == -)
return MatchingData();
l = max(l, );
r = min(amount, r);
if (l >= r)
return MatchingData();
return MatchingData(value(l), value(l + ), r - l);
}
} MatchingData; int n;
char* str;
//int *log2;
SuffixArray sa;
int f[bzmax][N]; inline void init(char* str, int _n) {
// log2 = new int[(n + 1)];
// log2[0] = -1;
// for (int i = 1; i <= n; i++)
// log2[i] = log2[i >> 1] + 1;
n = _n;
sa.set(n, str);
sa.build();
sa.get_height();
sa.init_st();
for (int k = ; ( << k) <= n; k++) {
int* F = f[k], len = ( << k);
for (int i = ; i + len <= n; i++)
F[i] = i;
sort(F, F + (n - len) + , [&] (const int& x, const int& y) {
int rt = sa.compare(x, x + len - , y, y + len - );
if (!rt)
return x < y;
return rt == -;
}); // it can be replace by radix sort
}
} pair<int, int> getRange(int s, int k) {
int len = << k, l = , r = n - len, mid;
int* F = f[k], L, R;
while (l <= r) {
mid = (l + r) >> ;
if (sa.compare(s, s + len - , F[mid], F[mid] + len - ) == )
l = mid + ;
else
r = mid - ;
}
L = r + ;
l = , r = n - len;
while (l <= r) {
mid = (l + r) >> ;
if (sa.compare(s, s + len - , F[mid], F[mid] + len - ) >= )
l = mid + ;
else
r = mid - ;
}
R = l - ;
return pair<int, int>(L, R);
} int succ(int s, int k, int i, int L, int R) { // pos >= i
int len = << k, l = , r = n - len;
int mid;
int *F = f[k];
if (L > R)
return inf;
l = L, r = R;
while (l <= r) {
mid = (l + r) >> ;
if (F[mid] >= i)
r = mid - ;
else
l = mid + ;
}
if (r == R)
return inf;
return F[r + ];
} int pred(int s, int k, int i) { //<= i
int len = << k, l = , r = n - len;
int L, R, mid;
int *F = f[k];
while (l <= r) {
mid = (l + r) >> ;
if (sa.compare(s, s + len - , F[mid], F[mid] + len - ) == )
l = mid + ;
else
r = mid - ;
}
L = r + ;
l = , r = n - len;
while (l <= r) {
mid = (l + r) >> ;
if (sa.compare(s, s + len - , F[mid], F[mid] + len - ) >= )
l = mid + ;
else
r = mid - ;
}
R = l - ;
if (L > R)
return -;
l = L, r = R;
while (l <= r) {
mid = (l + r) >> ;
if (F[mid] <= i)
l = mid + ;
else
r = mid - ;
}
if (l == L)
return -;
return F[l - ];
} // rt - lt + 1 = 2 ^ k
MatchingData query(int ls, int rs, int lt, int k) {
int len = << k;
pair<int, int> range = getRange(lt, k);
int a0 = succ(lt, k, ls, range.first, range.second);
if (a0 + len - > rs)
return MatchingData();
int a1 = succ(lt, k, a0 + , range.first, range.second);
if (a1 + len - > rs)
return MatchingData(a0);
int an = pred(lt, k, rs - len + );
assert(an >= ls);
MatchingData rt (a0, a1);
rt.amount = N;
rt.amount = rt.indexOf(an) + ;
return rt;
} } using IPM :: MatchingData; int n, m;
char str[N]; inline void init() {
scanf("%s", str);
n = strlen(str);
IPM :: init(str, n);
} int query(int l, int r) {
int t = , half_len = (r - l + ) >> ;
while (( << t) < half_len)
t++;
for (int i = t; ~i; i--) {
int len = min(r - l, << (i + )), hlen = ( << i);
MatchingData md_l = IPM :: query(l, l + len - , r - hlen + , i);
MatchingData md_r = IPM :: query(r - len + , r, l, i);
md_l = md_l - l + hlen;
md_r = -(~md_r) + (r + );
md_l = md_l & md_r;
if (md_l.amount)
return md_l.last();
}
return (str[l] == str[r] && l < r);
} inline void solve() {
scanf("%d", &m);
int l, r;
while (m--) {
scanf("%d%d", &l, &r);
printf("%d\n", query(--l, --r));
}
} int main() {
// freopen("border.in", "r", stdin);
// freopen("border.out", "w", stdout);
init();
solve();
return ;
}
luogu P4482 [BJWC2018] Border 的四种求法 - 后缀数组的更多相关文章
- luogu P4482 [BJWC2018]Border 的四种求法
luogu 对于每个询问从大到小枚举长度,哈希判断是否合法,AC 假的(指数据) 考虑发掘border的限制条件,如果一个border的前缀部分的末尾位置位置\(x(l\le x < r)\)满 ...
- 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree
原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...
- [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)
题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...
- [BJWC2018]Border 的四种求法
description luogu 给一个小写字母字符串\(S\),\(q\)次询问每次给出\(l,r\),求\(s[l..r]\)的\(Border\). solution 我们考虑转化题面:给定\ ...
- 【LuoguP4482】[BJWC2018]Border 的四种求法
题目链接 题意 区间 boder \(n,q\leq 2*10^5\) Sol (暴力哈希/SA可以水过) 字符串区间询问问题,考虑用 \(SAM\) 解决. boder相当于是询问区间 \([l,r ...
- 「BJWC2018」Border 的四种求法
「BJWC2018」Border 的四种求法 题目描述 给一个小写字母字符串 \(S\) ,\(q\) 次询问每次给出 \(l,r\) ,求 \(s[l..r]\) 的 Border . \(1 \l ...
- 【洛谷4482】Border的四种求法(后缀自动机_线段树合并_链分治)
这题我写了一天后交了一发就过了我好兴奋啊啊啊啊啊啊 题目 洛谷 4482 分析 这题明明可以在线做的,为什么我见到的所有题解都是离线啊 -- 什么时候有机会出一个在线版本坑人. 题目的要求可以转化为求 ...
- spring的依赖注入的四种方式,数组与集合注入;引用注入;内部bean注入
三种注入方式 第一种: 基于构造函数 hi.java (bean) package test_one; public class hi { private String name; public hi ...
- c语言 四种方法调用数组
#include <stdio.h> /********************************* * 方法1: 第一维的长度可以不指定 * * 但必须指定第二维的长度 * * ...
随机推荐
- ubus socket always in connecting status
When we try to transplant ubus to uclinux, ubusd can't run but "ubus list" will hang up. 1 ...
- 复制pdf文字出来是乱码
PDF文件复制文本为乱码 - longzhinuhou的博客 - CSDN博客 https://blog.csdn.net/longzhinuhou/article/details/83758966 ...
- c++第三次实验
第一题: 先把代码贴上来 main.cpp #include <iostream> #include <cstdlib> #include<conio.h> #in ...
- 《PHP内核剖析 - 变量/内存管理》
本文总结自: <PHP7 内核剖析 - 变量的内部实现> 一:变量的实现 - 变量是一个语言实现的基础. - 在PHP中,变量的组成部分为 变量名(zval) 变量值(zend_value ...
- Windows下使用TeamViewer连接远程服务器,以及解决“远程桌面关闭后TeamViewer不能连接”的问题
1.本地安装TeamViewer,完成后如下: 2.远程服务器也安装TeamViewer 在本地TeamViewer中得伙伴ID,输入远程的ID,弹出如下对话框,输入密码即可. 3.这时虽然可以连接, ...
- [ROS]激光驱动安装
参考资料: https://blog.csdn.net/hongliang2009/article/details/73302986 https://blog.csdn.net/bohaijun_12 ...
- JDK8 Stream操作整理
1,forEach this.quoteItemList.forEach(p -> p.setMode(mode)); 2,获取对话属性,去重后生成集合 List<String> p ...
- 24个 CSS 高级技巧合集
上期入口:史上最全实用网络爬虫合集! 1.使用CSS复位 CSS复位可以在不同的浏览器上保持一致的样式风格.您可以使用CSS reset 库Normalize等,也可以使用一个更简化的复位方法: ** ...
- ubuntu 16.04 搭建tigervnc
主要参考 https://vitux.com/ubuntu-vnc-server/ apt install xfce4 xfce4-goodies -yapt install -y tightvncs ...
- Java多线程处理List数据
实例1: 解决问题:如何让n个线程顺序遍历含有n个元素的List集合 import java.util.ArrayList; import java.util.List; import org.apa ...