题目链接
题意
将一串数( n≤1e6 )依次插入到一棵二叉排序树中, dfs 一遍,将经过的每个节点的信息加到一个串尾(如果当前节点为奇数则加 ′1′ 否则加 ′0′ )。最后再给一个模式串,问其在得到的串中出现了多少次。
思路
这道题的每一块都十分清晰,建树, dfs , kmp 。
然而问题就出在了数据量上。因此,要在两个方面进行优化。
1 . 插入到二叉排序树中:
这里有用到一个性质,那就是插入的节点的父亲,或者是大于它的最小值,或者是小于它的最大值,并且有且只有一个合法。
于是问题就转化成了树状数组求第
2
.
需要手写栈。
Code
#include <bits/stdc++.h>
#define maxn 600010
using namespace std;
typedef long long LL;
int id[maxn], ch[maxn][2], tot, a[maxn], f[7010], c[maxn], n, len, top, st[maxn];
char s[maxn * 3], P[7010];
bool vis[maxn];
void getfail() {
int m = strlen(P);
f[0] = f[1] = 0;
for (int i = 1; i < m; ++i) {
int j = f[i];
while (j && P[j] != P[i]) j = f[j];
f[i+1] = P[i] == P[j] ? j+1 : 0;
}
}
int kmp() {
int j = 0, l = len, m = strlen(P), cnt = 0;
for (int i = 0; i < l; ++i) {
while (j && s[i] != P[j]) j = f[j];
if (s[i] == P[j]) ++j;
if (j == m) ++cnt, j = f[j];
}
return cnt;
}
int kas;
void init() {
memset(c, 0, sizeof(c));
memset(ch, 0, sizeof ch);
}
int lowbit(int x) { return x & -x; }
void add(int x) { while (x <= n) ++c[x], x += lowbit(x); }
int sum(int x) { int ret = 0; while (x) ret += c[x], x -= lowbit(x); return ret; }
int query(int k) {
int l = 1, r = n;
while (r > l) {
int mid = l + r >> 1;
if (sum(mid) >= k) r = mid;
else l = mid+1;
}
return l;
}
void insert(int x, int n) {
add(x);
int k = sum(x), l, r;
if (k == 1) l = query(k+1), ch[l][0] = x;
else if (k == n) r = query(k-1), ch[r][1] = x;
else {
l = query(k+1), r = query(k-1);
if (!ch[r][1]) ch[r][1] = x;
else ch[l][0] = x;
}
}
void dfs(int u) {
memset(vis, 0, sizeof(vis)); top = len = 0;
st[top++] = u;
while (top > 0) {
int v = st[top-1];
s[len++] = v & 1 ? '1' : '0';
if (ch[v][0] && !vis[ch[v][0]]) { st[top++] = ch[v][0], vis[ch[v][0]] = true; continue; }
if (ch[v][1] && !vis[ch[v][1]]) { st[top++] = ch[v][1], vis[ch[v][1]] = true; continue; }
--top;
}
}
void work() {
init();
int x;
scanf("%d", &n);
scanf("%d", &x);
add(x); int rt = x;
for (int i = 2; i <= n; ++i) scanf("%d", &x), insert(x, i);
dfs(rt);
scanf("%s", P);
getfail();
printf("Case #%d: %d\n", ++kas, kmp());
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}