zoukankan      html  css  js  c++  java
  • 洛谷 P4770 [NOI2018]你的名字

    简明题意:你有一个字符串(S),每次询问一个字符串(T)和区间([l,r]),求(T)中不在(S[l,r])中出现的本质不同的子串个数

    不在(S[l,r])中出现可以转化成(T)的所有子串减去在(S[l,r])中出现

    首先考虑(l=1,r=|S|)时的做法

    我们对于(T)的每一个前缀([1,i])计算出最长的是(S)的子串的后缀长度

    这个很好求,先对(S)做后缀自动机,假设我们已经匹配到了(T)串的第i个字符,当前最长匹配长度为l,如果(S)的parent树上有出边为(T_i),那么就走到这个点,并且l++;否则就往上跳直到有(T_i)这条出边为止,然后l变为这个点的len然后再继续匹配就可以;跳到根还没有出边的话当前l就为0

    然后要求(T)的在(S[l,r])出现的本质不同的子串个数

    既然我们已经得到了上面的那个东西,那么只要计算出(T)的每个节点出现的本质不同的子串个数就可以了,这个直接对(T)做后缀自动机,然后([max(len_{fa_x},l),len_x])都可以算作答案

    那么推广到这个题上来

    思考上面在(S)的parent树上跳的那个过程,现在的是区间([l,r]),那么可能(fa_x)不在([l,r])里,也就是比l小,这样我们是不能转移的,所以我们考虑这个点的endpos的集合,我们应该找到一个位置p使得(p-len_x+1geq l),那么为了便于维护,我们要找到一个最大的(p-len_x+1),那也就是p最大

    于是这就是一个二维偏序,第一维是(pleq l),第二维是p要在x的子树中

    第一维直接对询问离线,然后对右端点排序,往右加点就可以

    第二维考虑对parent树dfs,然后这就是一个区间问题了

    有一点要注意的是,当(p-len_x+1le l)时,x的父亲可能会有左端点比l大,但是长度越过了l,跳点的时候还要加上这种情况

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define zrt k << 1
    #define yrt k << 1 | 1
    const int N = 5e5;
    using namespace std;
    int n,m,T,nxt[N * 2 + 5],head[N * 2 + 5],edge[N * 2 + 5],edge_cnt;
    int size[N * 2 + 5],dfn_cnt,dfn[N * 2 + 5],f[N * 2 + 5];
    long long ans[N + 5];
    char s[N + 5],t[N * 2 + 5];
    struct Q
    {
        int l,r,st,ed,id;
    }q[N + 5];
    struct sam
    {
        int fa[N * 2 + 5],len[N * 2 + 5],cnt,las,ch[N * 2 + 5][26],ep[N * 2 + 5],mp[N * 2 + 5];
        sam()
        {
            cnt = las = 1;
        }
        void clear()
        {
            for (int i = 1;i <= cnt;i++)
            {
                ep[i] = mp[i] = len[i] = fa[i] = 0;
                for (int j = 0;j < 26;j++)
                    ch[i][j] = 0;
            }
            cnt = las = 1;
        }
        void insert(int c,int id)
        {
            int q = ++cnt,p = las;
            las = q;
            len[q] = len[p] + 1;
            ep[q] = id;
            mp[id] = q;
            while (p && ! ch[p][c])
            {
                ch[p][c] = q;
                p = fa[p];
            }
            if (!p)
                fa[q] = 1;
            else
            {
                int x = ch[p][c];
                if (len[x] == len[p] + 1)
                    fa[q] = x;
                else
                {
                    int y = ++cnt;
                    ep[y] = id;
                    len[y] = len[p] + 1;
                    fa[y] = fa[x];
                    fa[x] = fa[q] = y;
                    for (int i = 0;i < 26;i++)
                        ch[y][i] = ch[x][i];
                    while (p && ch[p][c] == x)
                    {
                        ch[p][c] = y;
                        p = fa[p];
                    }
                }
            }
        }
    }a,b;
    int cmp(Q x,Q y)
    {
        return x.r < y.r;
    }
    void add_edge(int u,int v)
    {
        edge[++edge_cnt] = v;
        nxt[edge_cnt] = head[u];
        head[u] = edge_cnt;
    }
    void dfs(int u)
    {
        dfn[u] = ++dfn_cnt;
        size[u] = 1;
        for (int i = head[u];i;i = nxt[i])
        {
            int v = edge[i];
            dfs(v);
            size[u] += size[v];
        }
    }
    struct Seg
    {
        int mx[N * 8 + 5];
        void upd(int k)
        {
            mx[k] = max(mx[zrt],mx[yrt]);
        }
        void modify(int k,int l,int r,int x,int z)
        {
            if (l == r)
            {
                mx[k] = z;
                return;
            }
            int mid = l + r >> 1;
            if (x <= mid)
                modify(zrt,l,mid,x,z);
            else
                modify(yrt,mid + 1,r,x,z);
            upd(k);
        }
        int query(int k,int l,int r,int x,int y)
        {
            if (l >= x && r <= y)
                return mx[k];
            int mid = l + r >> 1;
            if (x > mid)
                return query(yrt,mid + 1,r,x,y);
            else
                if (y <= mid)
                    return query(zrt,l,mid,x,y);
                else
                    return max(query(zrt,l,mid,x,y),query(yrt,mid + 1,r,x,y));
        }
    }tree;
    int main()
    {
        scanf("%s",s + 1);
        n = strlen(s + 1);
        for (int i = 1;i <= n;i++)
            a.insert(s[i] - 'a',i);
        for (int i = 2;i <= a.cnt;i++)
            add_edge(a.fa[i],i);
        dfs(1);
        scanf("%d",&T);
        int l,r;
        m = 1;
        for (int i = 1;i <= T;i++)
        {
            scanf("%s",t + m);
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].id = i;
            q[i].st = m;
            m += strlen(t + m);
            q[i].ed = m - 1;
        }
        sort(q + 1,q + T + 1,cmp);
        for (int i = 1,j = 1;i <= T;i++)
        {
            while (j <= q[i].r)
            {
                tree.modify(1,1,dfn_cnt,dfn[a.mp[j]],j);
                j++;
            }
            for (int k = q[i].st;k <= q[i].ed;k++)
                b.insert(t[k] - 'a',k - q[i].st + 1);
            int u = 1,ll = 0;
            for (int k = q[i].st;k <= q[i].ed;k++)
            {
                int v = a.ch[u][t[k] - 'a'];
                if (v)
                    u = v,ll++;
                else
                {
                    u = a.fa[u];
                    while (u)
                    {
                        if (a.ch[u][t[k] - 'a'])
                        {
                            ll = a.len[u] + 1;
                            u = a.ch[u][t[k] - 'a'];
                            break;
                        }
                        u = a.fa[u];
                    }
                    if (!u)
                        u = 1,ll = 0;
                }
                while (u)
                {
                    int mx = tree.query(1,1,dfn_cnt,dfn[u],dfn[u] + size[u] - 1);
                    if (mx && mx - ll + 1 >= q[i].l)
                        break;
                    if (mx && mx - a.len[a.fa[u]] + 1 > q[i].l)
                    {
                        ll = mx - q[i].l + 1;
                        break;
                    }
                    u = a.fa[u];
                    ll = a.len[u];
                }
                f[k - q[i].st + 1] = ll;
            }
            for (int k = 2;k <= b.cnt;k++)
                ans[q[i].id] += max(b.len[k] - max(f[b.ep[k]],b.len[b.fa[k]]),0);
            b.clear();
        }
        for (int i = 1;i <= T;i++)
            printf("%lld
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    MVC 路由规则
    MVC系统过滤器、自定义过滤器
    MVC部署
    MVC 读书笔记
    C# 调用 Web Service
    RESTful 架构
    WebSocket C# Demo
    C# 编写服务 Windows service
    C# 调用FFmpeg 根据图片合成视频
    Socket 编程示例(二)
  • 原文地址:https://www.cnblogs.com/sdlang/p/13073720.html
Copyright © 2011-2022 走看看