Loj2059. 「TJOI / HEOI2016」字符串
題意:給定一個串,問
考慮將串反轉,則變成了最長公共後綴問題。
二分答案
考慮用線段樹合併維護
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
int lc[MAXN*50], rc[MAXN*50], top = 0;
int build(int &nd, int pos, int L, int R)
{
nd = ++top;
if (L == R) return nd;
else {
int mid = (L+R)>>1;
if (pos <= mid) return build(lc[nd], pos, L, mid);
else return build(rc[nd], pos, mid+1, R);
}
}
int merge(int a, int b)
{
if (a == 0 || b == 0) return a+b;
int c = ++top;
lc[c] = merge(lc[a], lc[b]), rc[c] = merge(rc[a], rc[b]);
return c;
}
bool query(int nd, int opl, int opr, int L, int R)
{
if (!nd) return 0;
if (opl == L && opr == R) return 1;
else {
int mid = (L+R)>>1;
if (opr <= mid) return query(lc[nd], opl, opr, L, mid);
else if (opl > mid) return query(rc[nd], opl, opr, mid+1, R);
else return query(lc[nd], opl, mid, L, mid)||query(rc[nd], mid+1, opr, mid+1, R);
}
}
int chl[MAXN*2][26], fa[MAXN*2][21], maxl[MAXN*2], sam_top = 1, root = 1, last = 1;
int rt[MAXN*2], fin[MAXN*2];
int n, m;
char str[MAXN*2];
void push(int x, int id)
{
int p = last, np = ++sam_top; maxl[np] = maxl[p]+1, build(rt[np], id, 1, n);
while (p && !chl[p][x]) chl[p][x] = np, p = fa[p][0];
if (!p) fa[np][0] = root;
else {
int q = chl[p][x];
if (maxl[q] == maxl[p]+1) fa[np][0] = q;
else {
int nq = ++sam_top; maxl[nq] = maxl[p]+1;
memcpy(chl[nq], chl[q], sizeof chl[q]);
fa[nq][0] = fa[q][0], fa[q][0] = fa[np][0] = nq;
while (p && chl[p][x] == q) chl[p][x] = nq, p = fa[p][0];
}
}
fin[id] = last = np;
}
struct node {
int to, next;
} edge[MAXN*2];
int head[MAXN*2], tree_top = 0;
void push_tree(int i, int j)
{ edge[++tree_top] = (node) {j, head[i]}, head[i] = tree_top; }
void dfs(int nd)
{
// for (int i = 1; i <= tab; i++) cerr << " ";
// cerr << nd << endl;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
dfs(to), rt[nd] = merge(rt[nd], rt[to]);
}
}
void init()
{
scanf("%d%d", &n, &m);
scanf("%s", str+1);
reverse(str+1, str+n+1);
for (int i = 1; i <= n; i++)
push(str[i]-'a', i);
for (int j = 1; j < 20; j++)
for (int i = 1; i <= sam_top; i++)
fa[i][j] = fa[fa[i][j-1]][j-1];
for (int i = 2; i <= sam_top; i++) {
push_tree(fa[i][0], i);
// cerr << i << "," << fa[i][0] << endl;
}
dfs(root);
}
bool judge(int pos, int mid, int a, int b)
{
for (int i = 19; i >= 0; i--)
if (maxl[fa[pos][i]] >= mid)
pos = fa[pos][i];
/*cerr << pos << " " << rt[pos] << " " << a-mid+1 << " " << b << endl;
for (int i = 1; i <= 5; i++)
cerr << query(rt[pos], i, i, 1, n) << " ";
cerr << endl;*/
return query(rt[pos], a+mid-1, b, 1, n);
}
int main()
{
init();
for (int i = 1; i <= m; i++) {
int a, b, c, d;
scanf("%d%d%d%d", &b, &a, &d, &c);
a = n-a+1, b = n-b+1, c = n-c+1, d = n-d+1;
int pos = fin[d];
int L = 1, R = min(b-a+1, d-c+1), mid;
while (L <= R) {
mid = (L+R)>>1;
if (judge(pos, mid, a, b)) L = mid+1;
else R = mid-1;
}
printf("%d\n", L-1);
}
return 0;
}