HDU 5801 Up Sky,Mr.Zhu(可持久化Trie)

题意:

$给定N\le 10^5的字符串S,字符集大小为5,其中的回文子串长度<20$
$定义回文子串str[0\ldots n-1]的特征串为str[\lfloor n/ 2\rfloor\ldots n-1]$
$给定询问区间s[L\ldots R]里,特征串前缀为T的回文串有多少个,|T|\le 10$

分析:

$区间询问就是裸的可持久化Trie$
$以每个字符s[i]为结尾建立每棵Trie,暴力把以s[i]结尾的全部特征串插进去$
$由于区间询问的时候要保证回文串也在这个范围内,这么做是有问题的$
$但是特征串长度在[1, 10],所以可以暴力对每个长度建立可持久Trie$
$这样空间是10\times N\times 10\times 5,就炸了$
$所以折衷一下,离线询问,枚举每个特征串长度,每次重建可持久化Trie就行$
$为了方便处理奇偶回文,可以枚举回文长度,注意各种合法边界,然后就没啥了$
$时间复杂度O(n\times 10^2+q\times 10)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//
// Created by TaoSama on 2016-08-13
// Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
typedef long long LL;
int root[N];
struct PersistentTrie {
static const int M = N * 10, S = 5;
int sz;
struct Node {
LL val;
int nxt[S];
} dat[M];
void init() {
sz = 0;
memset(&dat[0], 0, sizeof dat[0]);
}
int newNode(int rt) {
dat[++sz] = dat[rt];
return sz;
}
void update(char* s, int n, int& rt) {
rt = newNode(rt);
int u = rt;
for(int i = 0; i < n; ++i) {
int c = s[i] - 'a';
int& v = dat[u].nxt[c];
v = newNode(v);
++dat[v].val;
u = v;
}
}
LL query(char* s, int rt) {
int u = rt;
for(int i = 0; s[i]; ++i) {
int c = s[i] - 'a';
u = dat[u].nxt[c];
}
return dat[u].val;
}
} trie;
int q;
char s[N], t[N][15];
int l[N], r[N];
LL ans[N];
bool check(char* s, int len) {
for(int i = 0; i < len / 2; ++i)
if(s[-i] != s[-(len - i - 1)]) return false;
return true;
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
while(scanf("%s%d", s + 1, &q) == 2) {
int n = strlen(s + 1);
for(int i = 1; i <= q; ++i) scanf("%d%d%s", l + i, r + i, t[i]);
memset(ans, 0, sizeof ans);
for(int len = 1; len < 20; ++len) {
trie.init();
for(int i = 1; i <= n; ++i) {
root[i] = root[i - 1];
if(i < len) continue;
bool ok = check(s + i, len);
if(!ok) continue;
int l = i - (len - 1) / 2;
trie.update(s + l, (len + 1) / 2, root[i]);
}
for(int i = 1; i <= q; ++i) {
if(r[i] - l[i] + 1 < len) continue;
ans[i] += trie.query(t[i], root[r[i]]) - trie.query(t[i], root[l[i] + len - 2]);
}
}
for(int i = 1; i <= q; ++i)
printf("%I64d\n", ans[i]);
}
return 0;
}

1. 除非注明,本博文即为原创,转载请注明链接地址
2. 本博文只代表博主当时的观点或结论,请不要恶意攻击
3. 如果本文帮到了您,不妨点一下 下面分享到 按钮,让更多的人看到