bzoj2555

后缀自动机+LCT

终于做了这道题

思路比较明显,每次的答案就是走到的最终节点的Right集合大小,如果走不到就是0。但是问题在于每次添加字符后parent树的形态变了,那么Right集合也要变化,这个我们用LCT维护,由于是有根树,比较好维护。

#include<bits/stdc++.h>
using namespace std;
const int N = 1.2e6 + 5;
struct node {
    int val, par;
    int ch[26];
} t[N];
int n, m, mask, top;
int st[N];
char opt[20], s[N << 1];
void decode(char *s, int mask)
{
    int len = strlen(s);
    for(int i = 0; i < len; ++i) 
    {
        mask = (mask * 131 + i) % len;
        swap(s[i], s[mask]);
    }
}
namespace LCT
{
    int fa[N], ch[N][2], tag[N], sum[N];
    void paint(int x, int d)
    {
        if(!x) return;
        tag[x] += d;
        sum[x] += d;
    }
    bool wh(int x) 
    {
        return x == ch[fa[x]][1];
    }
    bool isr(int x) 
    {
        return !fa[x] || (ch[fa[x]][0] != x && ch[fa[x]][1] != x);
    }
    void pushdown(int x)
    {
        if(tag[x])
        {
            paint(ch[x][0], tag[x]);
            paint(ch[x][1], tag[x]);
            tag[x] = 0;
        }
    }
    void up(int x) 
    {
        top = 0;
        while(!isr(x)) 
        {
            st[++top] = x;
            x = fa[x];
        }
        st[++top] = x;
        for(int i = top; i; --i) pushdown(st[i]);
    }
    void rotate(int x)
    {
        int f = fa[x], t = wh(x);
        fa[x] = fa[f];
        if(!isr(f)) ch[fa[f]][wh(f)] = x;
        fa[f] = x;
        ch[f][t] = ch[x][t ^ 1];
        fa[ch[x][t ^ 1]] = f;
        ch[x][t ^ 1] = f;
    }
    void splay(int x) 
    {
        up(x);
        while(!isr(x)) 
        {
            if(!isr(fa[x])) rotate(wh(x) == wh(fa[x]) ? fa[x] : x);
            rotate(x);
        }   
    }
    void access(int x)
    {
        for(int f = 0; x; f = x, x = fa[x]) 
        {
            splay(x);
            ch[x][1] = f;
        }
    }
    void link(int x, int y)
    {
        fa[x] = y;
        access(y);
        splay(y);
        paint(y, sum[x]);
    }
    void cut(int x)
    {
        access(x);
        splay(x);
        paint(ch[x][0], -sum[x]);
        fa[ch[x][0]] = 0;
        ch[x][0] = 0; 
    }
} using namespace LCT;
namespace SAM 
{
    int last = 1, sz = 1, root = 1;
    int nw(int x)
    {
        t[++sz].val = x;
        return sz;
    }
    void extend(int c)
    {
        int p = last, np = nw(t[p].val + 1);
        sum[np] = 1;
        while(p && !t[p].ch[c]) t[p].ch[c] = np, p = t[p].par;
        if(!p) t[np].par = root, link(np, root);
        else
        {
            int q = t[p].ch[c];
            if(t[q].val == t[p].val + 1) t[np].par = q, link(np, q);
            else
            {
                int nq = nw(t[p].val + 1);
                memcpy(t[nq].ch, t[q].ch, sizeof(t[q].ch));
                link(nq, t[q].par);
                cut(q);
                link(q, nq);
                link(np, nq);
                t[nq].par = t[q].par;
                t[q].par = t[np].par = nq;
                while(p && t[p].ch[c] == q) t[p].ch[c] = nq, p = t[p].par;
            }
        }
        splay(np);
        last = np;
    }
    void add(char *s)
    {
        int len = strlen(s);
        for(int i = 0; i < len; ++i) extend(s[i] - 'A');
    }
    void query(char *s)
    {
        int len = strlen(s), u = root;
        for(int i = 0; i < len; ++i)
        {
            if(!t[u].ch[s[i] - 'A']) 
            {
                puts("0");
                return;
            }
            u = t[u].ch[s[i] - 'A'];
        }
        up(u);
        printf("%d\n", sum[u]);
        mask ^= sum[u];
    }
} using namespace SAM;
int main()
{
    scanf("%d%s", &m, s);
    n = strlen(s);
    for(int i = 0; i < n; ++i) extend(s[i] - 'A');
    while(m--)
    {
        scanf("%s%s", opt, s);
        decode(s, mask);
        if(opt[0] == 'A') add(s);
        if(opt[0] == 'Q') query(s);
    }
    return 0;
}
View Code

 

posted @ 2017-11-19 19:30  19992147  阅读(109)  评论(0编辑  收藏  举报