zoukankan      html  css  js  c++  java
  • 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
    ", 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
  • 相关阅读:
    Android学习笔记【07】【四大组件之广播接收者】
    Android Adapter、Activity回传数据、发送短信
    Android学习笔记【06】【四大组件之Activity】
    Android学习笔记【05】【网络编程之二】
    Android学习笔记【04】【网络编程之一】
    Android学习笔记【03】【数据存储与数据展示】
    【转】sql server获取数据库名,表明,表结构
    C# 打开默认浏览器
    winform 重绘listbox
    字符串数组的简单应用,字符换行,c#,asp.net
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7860838.html
Copyright © 2011-2022 走看看