• BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay


    BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay

    Description

    魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1、2 拼凑起来形成一个魔咒串 [1,2]。
    一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。
    例如 S=[1,2,1] 时,它的生成魔咒有 [1]、[2]、[1,2]、[2,1]、[1,2,1] 五种。S=[1,1,1] 时,它的生成魔咒有 [1]、
    [1,1]、[1,1,1] 三种。最初 S 为空串。共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符。每次操作后都
    需要求出,当前的魔咒串 S 共有多少种生成魔咒。

    Input

    第一行一个整数 n。
    第二行 n 个数,第 i 个数表示第 i 次操作加入的魔咒字符。
    1≤n≤100000。,用来表示魔咒字符的数字 x 满足 1≤x≤10^9

    Output

    输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量

    Sample Input

    7
    1 2 3 3 3 1 2

    Sample Output

    1
    3
    6
    9
    12
    17
    22

    在后面添加字符每次会产生若干个后缀。于是翻转一下相当于每次只添加一个后缀。
    然后如何求不同的子串个数呢?
    首先对于一个后缀$Suffix(i)$,会贡献$n-i+1$个子串,但这些子串会有一些重复的,于是找$rank[i]$的前驱和后继所在的后缀设为$j$。
    那么会有$Lcp(suffix(i),suffix(j))$这么多是重复的。
    于是用splay维护前驱后继,然后ST表求两个后缀的LCP。
     
    代码:
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 100050
    #define ls ch[p][0]
    #define rs ch[p][1]
    #define get(x) (ch[f[x]][1]==x)
    typedef long long ll;
    int n,ws[N],wv[N],wa[N],wb[N],rank[N],sa[N],height[N],r[N];
    int f[N],ch[N][2],siz[N],rt,val[N],reimu;
    //////////////////////////////////////////////
    struct A {
        int num,id,v;
    }a[N];
    bool cmp1(const A &x,const A &y){return x.num<y.num;}
    bool cmp2(const A &x,const A &y){return x.id<y.id;}
    ///////////////////////////////////////////////
    void build_suffix_array() {
        int i,j,p,*x=wa,*y=wb,*t,m=n;
        for(i=0;i<m;i++) ws[i]=0;
        for(i=0;i<n;i++) ws[x[i]=r[i]]++;
        for(i=1;i<m;i++) ws[i]+=ws[i-1];
        for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
        for(j=p=1;p<n;j<<=1,m=p) {
            for(p=0,i=n-j;i<n;i++) y[p++]=i;
            for(i=0;i<n;i++) if(sa[i]-j>=0) y[p++]=sa[i]-j;
            for(i=0;i<n;i++) wv[i]=x[y[i]];
            for(i=0;i<m;i++) ws[i]=0;
            for(i=0;i<n;i++) ws[wv[i]]++;
            for(i=1;i<m;i++) ws[i]+=ws[i-1];
            for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
            for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;i++) {
                if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]) x[sa[i]]=p-1;
                else x[sa[i]]=p++;
            }
        }
        for(i=1;i<n;i++) rank[sa[i]]=i;
        for(i=p=0;i<n-1;height[rank[i++]]=p)
            for(p?p--:0,j=sa[rank[i]-1];r[i+p]==r[j+p];p++);
    }
    /////////////////////////////////////////////
    int newnode(int x) {
        siz[++reimu]=1; val[reimu]=x; return reimu;
    }
    void pushup(int p) {
        siz[p]=siz[ls]+siz[rs]+1;
    }
    void rotate(int x) {
        int y=f[x],z=f[y],k=get(x);
        ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
        ch[x][!k]=y; f[y]=x; f[x]=z;
        if(z) ch[z][ch[z][1]==y]=x;
        pushup(y); pushup(x);
        if(rt==y) rt=x;
    }
    void splay(int x,int y) {
        for(int fa;(fa=f[x])!=y;rotate(x)) 
            if(f[fa]!=y)
                rotate(get(x)==get(fa)?fa:x);
    }
    void insert(int x) {
        int p=rt,l,r;
        while(p) {
            if(val[p]>=x) r=p,p=ls;
            else l=p,p=rs;
        }
        splay(l,0); splay(r,rt);
        ch[r][0]=newnode(x);
        f[reimu]=r; pushup(r); pushup(l);
    }
    int pre(int x) {
        int p=rt,ans;
        while(p) {
            if(val[p]>=x) p=ls;
            else ans=p,p=rs;
        }
        return val[ans];
    }
    int nxt(int x) {
        int p=rt,ans;
        while(p) {
            if(val[p]<=x) p=rs;
            else ans=p,p=ls;
        }
        return val[ans];
    }
    /////////////////////////////////////////
    struct ST {
        int f[N][20],L[N];
        void init() {
            int i,j;
            memset(f,0x3f,sizeof(f));
            L[1]=0;
            for(i=2;i<=n;i++) L[i]=L[i>>1]+1;
            for(i=0;i<=n;i++) {
                f[i][0]=height[i];
            }
            for(j=1;(1<<j)<=n;j++) {
                for(i=0;i+(1<<j)-1<=n;i++) {
                    f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
                }
            }
        }
        int get_min(int l,int r) {
            int len=L[r-l+1];
            return min(f[l][len],f[r-(1<<len)+1][len]);
        }
    }S;
    int main() {
        scanf("%d",&n);
        int i;
        for(i=1;i<=n;i++) scanf("%d",&a[n-i+1].num),a[i].id=i;
        sort(a+1,a+n+1,cmp1);
        int j=0;a[0].num=23333443;
        for(i=1;i<=n;i++) {
            if(a[i].num!=a[i-1].num) j++;
            a[i].v=j;
        }
        sort(a+1,a+n+1,cmp2);
        for(i=0;i<n;i++) {
            r[i]=a[i+1].v;
        }
        r[n++]=0;
        build_suffix_array();
     
        /*for(i=0;i<n;i++) printf("%d ",r[i]); puts("");
        for(i=0;i<n;i++) printf("%d ",sa[i]); puts("");
        for(i=0;i<n;i++) printf("%d ",height[i]); puts("");
        for(i=0;i<n;i++) printf("%d ",rank[i]);puts("");*/
     
        ll ans=0;
        rt=newnode(-100000000);
        ch[rt][1]=newnode(100000000);
        f[ch[rt][1]]=rt;
        pushup(rt);
     
        S.init();
        for(i=n-2;i>=0;i--) {
            ans+=n-i-1;
            int pr=pre(rank[i]);
            int tmp=0;
            if(pr>=0) {
                tmp=S.get_min(pr+1,rank[i]);
            }
            int nx=nxt(rank[i]);
            if(nx<=n) {
                tmp=max(tmp,S.get_min(rank[i]+1,nx));
            }
            ans-=tmp;
            insert(rank[i]);
            printf("%lld
    ",ans);
        }
    }
    /*
    7
    1 2 3 3 3 1 2
    */
    
  • 相关阅读:
    windows编程:第一个windows程序
    百度地图API多个点聚合时,标注添加的标签label地图刷新就丢失的问题解决
    在WPF的WebBrowser控件中屏蔽脚本错误的提示
    使用SQL语句逐条更新每条记录
    通过 HDU 2048 来初步理解动态规划
    一个乱码问题
    2、设置配置文件
    1、搭建 maven 环境
    MyBatis 缓存机制
    关于 Mybatis 设置懒加载无效的问题
  • 原文地址:https://www.cnblogs.com/suika/p/9022854.html
Copyright © 2020-2023  润新知