HDU 4125 Moles 二叉排序树 树状数组 kmp

来源:互联网 发布:美国历史书籍推荐知乎 编辑:程序博客网 时间:2024/05/27 20:52

题目链接

题意

将一串数(n1e6)依次插入到一棵二叉排序树中,dfs一遍,将经过的每个节点的信息加到一个串尾(如果当前节点为奇数则加1否则加0)。最后再给一个模式串,问其在得到的串中出现了多少次。

思路

这道题的每一块都十分清晰,建树,dfskmp

然而问题就出在了数据量上。因此,要在两个方面进行优化。

1. 插入到二叉排序树中:

这里有用到一个性质,那就是插入的节点的父亲,或者是大于它的最小值,或者是小于它的最大值,并且有且只有一个合法。
于是问题就转化成了树状数组求第k大元素(先暂时写了个二分的两个log,明天再去翻翻看之前的博客写过的一个log的算法补上= =还看到有人写笛卡尔树和线段树明天再看情况补)。

2. dfs

需要手写栈。

Code

#include <bits/stdc++.h>#define maxn 600010using 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;}