hnjx2015 hashit

题意:
一个串,资瓷末端插入,删除一个字符,求每次操作后本质不同的子串个数;
题解:
“可持久化”后缀自动机裸题,类似按zhi并查集的“可持久化”,复杂度 O(N)
当时考场上的神犇大多是这么A的;
作死写了一发替罪羊树搞的后缀平衡树,代码感觉不长,实际比较长。。。
hash比较版本 O(NLog2N)

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define seed 123
#define ls ch[x][0]
#define rs ch[x][1]
using namespace std;
const int N=2e5+7;
typedef unsigned long long ll;
typedef double db;
const db alpha=0.6;
char s[N],c[N];
int n,now,ch[N][2],sz[N],rt=0,goat=0,stk[N],top;
ll ans=0;
ll H[N],pw[N],his[N];
ll getha(int l,int r){
    return H[r] - pw[r-l+1]*H[l-1];
}
void up(int x){
    sz[x]=sz[ls] + 1 + sz[rs];
}
int lcp(int x,int y){
    int l=0,r=min(x,y);
    while(l<r){
        int mid=(l+r+1)>>1;
        if(getha(x-mid+1,x) == getha(y-mid+1,y))l=mid;
        else r=mid-1;
    }
    return l;
}
bool cmp(int x,int y){
    int l=lcp(x,y);

    if(l==x)return true;
    if(l==y)return false;

    if(c[x-l]<c[y-l])return true;
    else return false;
}
void del(int& x,int goal){
    if(x==goal){
        if(!(ls*rs)){int cls=ls,crs=rs;ls=rs=0;x=cls+crs;return;}
        else{
            int who=ls;
            for(;ch[who][1];who=ch[who][1]);
            del(rt,who);

            ch[who][0]=ls;
            ch[who][1]=rs;
            ls=rs=0;
            x=who;
            up(x);
        }
    }
    else{
        int op=cmp(x,goal);
        if(!op)del(ls,goal);
        else del(rs,goal);
        up(x);
    }
}
void ins(int& x){
    if(!x){x=now,sz[x]=1;}
    else{
        int op=cmp(x,now);
        if(!op)ins(ls);
        else ins(rs);
        up(x);
        if(max(sz[ls],sz[rs]) > alpha*sz[x])goat=x;
    }
}
void dfs(int x){
    if(!x)return;
    dfs(ls);
    stk[++top]=x;
    dfs(rs);
}
void dfs_2(int& x,int l,int r){
    if(l>r){x=0;return;}
    int mid=(l+r)>>1;
    x=stk[mid];
    dfs_2(ls,l,mid-1);
    dfs_2(rs,mid+1,r);
    up(x);
}
void build(int& x){
    top=0;
    dfs(x);
    dfs_2(x,1,top);
}
void rebuild(int& x){
    if(x==goat){build(x);}
    else{
        int op=cmp(x,goat);
        if(!op)rebuild(ls);
        else rebuild(rs);
        up(x);
    }
}
int rank(int x){
    int cc=rt,res=0;
    for(;;){
        if(cc==x){res+=sz[ls];break;}
        int op=cmp(cc,x);
        if(op)res+=sz[ch[cc][0]] + 1,cc=ch[cc][1];
        else cc=ch[cc][0];
    }
    return res+1;
}
int kth(int k){
    int cc=rt;
    for(;;){
        if(!cc)return cc;
        if(sz[ch[cc][0]] + 1 == k)return cc;
        else if(sz[ch[cc][0]] >= k)cc=ch[cc][0];
        else{
            k-=sz[ch[cc][0]] + 1;
            cc=ch[cc][1];
        }
    }
}
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    pw[0]=1;rep(i,1,n)pw[i]=pw[i-1]*seed;
    rep(i,1,n){
        if(s[i]=='-'){
            del(rt,now);
            now--;
            printf("%llu\n",(ans=his[now]));
        }else{
            c[++now]=s[i]-'a';
            H[now]=seed*H[now-1]+c[now]+1;
            ins(rt);
            int rk;
            rk=rank(now);

            int fr=kth(rk-1);
            int suf=kth(rk+1);

            int mx=max(lcp(now,fr),lcp(now,suf));
            his[now]=(ans+=(now-mx));
            printf("%llu\n",his[now]);
        }
        if(goat)rebuild(rt),goat=0;
    }
}

动态标号版本 O(NLogN)

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define seed 123
#define ls ch[x][0]
#define rs ch[x][1]
using namespace std;
const int N=2e5+7;
typedef unsigned long long ll;
typedef double db;
const db alpha=0.6;
char s[N],c[N];
int n,now,ch[N][2],sz[N],rt=0,goat=0,stk[N],top;
ll ans=0;
ll H[N],pw[N],his[N];
db L[N],R[N],tag[N];
ll getha(int l,int r){
    return H[r] - pw[r-l+1]*H[l-1];
}
void up(int x){
    sz[x]=sz[ls] + 1 + sz[rs];
}
int lcp(int x,int y){
    int l=0,r=min(x,y);
    while(l<r){
        int mid=(l+r+1)>>1;
        if(getha(x-mid+1,x) == getha(y-mid+1,y))l=mid;
        else r=mid-1;
    }
    return l;
}
bool cmp(int x,int y){
    if(c[x]<c[y])return true;
    else if(c[x]>c[y])return false;
    else return tag[x-1] < tag[y-1];
}
void del(int& x,int goal){
    if(x==goal){
        if(!(ls*rs)){int cls=ls,crs=rs;ls=rs=L[x]=R[x]=0;x=cls+crs;return;}
        else{
            int who=ls;
            for(;ch[who][1];who=ch[who][1]);
            del(rt,who);

            ch[who][0]=ls;
            ch[who][1]=rs;
            L[who]=L[x];
            R[who]=R[x];
            tag[who]=tag[x];
            ls=rs=L[x]=R[x]=tag[x]=0;

            x=who;
            up(x);
        }
    }
    else{
        int op=cmp(x,goal);
        if(!op)del(ls,goal);
        else del(rs,goal);
        up(x);
    }
}
void ins(int& x,db dl,db dr){
    if(!x){x=now,sz[x]=1;L[x]=dl,R[x]=dr,tag[x]=(dl+dr)/2;}
    else{
        dl=L[x],dr=R[x];

        int op=cmp(x,now);

        db dmid=(dl+dr)/2;

        if(!op)ins(ls,dl,dmid);
        else ins(rs,dmid,dr);
        up(x);
        if(max(sz[ls],sz[rs]) > alpha*sz[x])goat=x;
    }
}
void dfs(int x){
    if(!x)return;
    dfs(ls);
    stk[++top]=x;
    dfs(rs);
}
void dfs_2(int& x,int l,int r,db dl,db dr){
    if(l>r){x=0;return;}
    int mid=(l+r)>>1;
    db dmid=(dl+dr)/2;

    x=stk[mid];
    tag[x]=dmid;
    L[x]=dl,R[x]=dr;

    dfs_2(ls,l,mid-1,dl,dmid);
    dfs_2(rs,mid+1,r,dmid,dr);
    up(x);
}
void build(int& x,db& l,db& r){
    top=0;
    dfs(x);
    dfs_2(x,1,top,l,r);
}
void rebuild(int& x){
    if(x==goat){build(x,L[x],R[x]);}
    else{
        int op=cmp(x,goat);
        if(!op)rebuild(ls);
        else rebuild(rs);
        up(x);
    }
}
int rank(int x){
    int cc=rt,res=0;
    for(;;){
        if(cc==x){res+=sz[ls];break;}
        int op=cmp(cc,x);
        if(op)res+=sz[ch[cc][0]] + 1,cc=ch[cc][1];
        else cc=ch[cc][0];
    }
    return res+1;
}
int kth(int k){
    int cc=rt;
    for(;;){
        if(!cc)return cc;
        if(sz[ch[cc][0]] + 1 == k)return cc;
        else if(sz[ch[cc][0]] >= k)cc=ch[cc][0];
        else{
            k-=sz[ch[cc][0]] + 1;
            cc=ch[cc][1];
        }
    }
}
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    pw[0]=1;rep(i,1,n)pw[i]=pw[i-1]*seed;
    rep(i,1,n){
        if(s[i]=='-'){
            del(rt,now);
            now--;
            printf("%llu\n",(ans=his[now]));
        }else{
            c[++now]=s[i]-'a';
            H[now]=seed*H[now-1]+c[now]+1;
            ins(rt,0,(1<<30));
            int rk;
            rk=rank(now);

            int fr=kth(rk-1);
            int suf=kth(rk+1);

            int mx=max(lcp(now,fr),lcp(now,suf));
            his[now]=(ans+=(now-mx));
            printf("%llu\n",his[now]);
        }
        if(goat)rebuild(rt),goat=0;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值