two strings

A1484. two strings(罗干)

时间限制1.0s   内存限制256.0MB
【问题描述】
  给定两个字符串A和B,有五种操作,操作1为在A串开头添加一个字符,操作2为在A串结尾添加一个字符,操作3为在B串开头添加一个字符,操作4为在B串结尾添加一个字符,操作5为询问当前的B串在当前A串中出现的次数。保证字符均为小写字母,且A、B串初始非空。
【输入格式】
  第一行第二行分别为初始的A串和B串;
  第三行一个整数m,表示操作的次数;
  接下来m行,每行表示一个操作,每行第一个数为一个在1-5之间的数字,若其值不为5,则在数字后会有一个小写字母。
【输出格式】
  对于每个询问,每行输出一个整数,表示B串在A串中出现的次数。
【样例输入】
  ababc
  a
  7
  5
  4 b
  5
  3 a
  1 a
  5
  5
【样例输出】
  2
  2
  1
  1
【数据规模】
  10%的数据中,最终A串和B串长度之和小于等于200,操作数小于等于10。
  30%的数据中,最终A串和B串长度之和小于等于2000,操作数小于等于1000。
  100%的数据中,最终A串和B串长度之和小于等于200000,操作数小于等于200000。
分析:对最终的A串和B串用分隔符拼接,构建后缀数组,模拟这m次操作;
   可以发现对于在A串或B串添加字符,最多会影响一个位置的可行性;
   在后缀数组中查找字符串可以使用二分找到连续区间,询问区间的合法性可以使用树状数组实现;
代码:
  
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10,inf=0x3f3f3f3f;
int n,m,k,t,d[maxn],tot;
void add(int x,int y){while(x<=tot)d[x]+=y,x+=x&(-x);}
int get(int x){int ret=0;while(x)ret+=d[x],x-=x&(-x);return ret;}
struct query{int op,pos;}q[maxn];
struct node{int x,id,nt;}e[maxn];
char ch[maxn];
int cntA[maxn],cntB[maxn];
int sa[maxn],lev[maxn],height[maxn];
int A[maxn],B[maxn],tsa[maxn];
int mi[20][maxn],p[maxn];
int ask(int l,int r)
{
    int x=p[r-l+1];
    return min(mi[x][l],mi[x][r-(1<<x)+1]);
}
void solve(int n,int m)
{
    for (int i = 0; i < m; i ++) cntA[i] = 0;
    for (int i = 1; i <= n; i ++) cntA[ch[i]] ++;
    for (int i = 1; i < m; i ++) cntA[i] += cntA[i - 1];
    for (int i = n; i; i --) sa[cntA[ch[i]] --] = i;
    lev[sa[1]] = 1;
    for (int i = 2; i <= n; i ++)
    {
        lev[sa[i]] = lev[sa[i - 1]];
        if (ch[sa[i]] != ch[sa[i - 1]]) lev[sa[i]] ++;
    }
    for (int l = 1; lev[sa[n]] < n; l <<= 1)
    {
        memset(cntA,0,sizeof(cntA[0])*(n+1));
        memset(cntB,0,sizeof(cntB[0])*(n+1));
        for (int i = 1; i <= n; i ++)
        {
            cntA[A[i] = lev[i]] ++;
            cntB[B[i] = (i + l <= n) ? lev[i + l] : 0] ++;
        }
        for (int i = 1; i <= n; i ++) cntB[i] += cntB[i - 1];
        for (int i = n; i; i --) tsa[cntB[B[i]] --] = i;
        for (int i = 1; i <= n; i ++) cntA[i] += cntA[i - 1];
        for (int i = n; i; i --) sa[cntA[A[tsa[i]]] --] = tsa[i];
        lev[sa[1]] = 1;
        for (int i = 2; i <= n; i ++)
        {
            lev[sa[i]] = lev[sa[i - 1]];
            if (A[sa[i]] != A[sa[i - 1]] || B[sa[i]] != B[sa[i - 1]]) lev[sa[i]] ++;
        }
    }
    for (int i = 1, j = 0; i <= n; i ++)
    {
        if (j) j --;
        while (ch[i + j] == ch[sa[lev[i] - 1] + j]) j ++;
        height[lev[i]] = j;
    }
}
int main() {
    int i,j;
    //freopen("in.txt","r",stdin);
    tot=0;
    int ha=-1,ta=-1,hb=-1,tb=-1;
    scanf("%s",ch+1);
    for(i=1;ch[i];i++)
    {
        e[tot].x=ch[i]-'a';
        if(!~ha)ha=ta=tot;
        else e[ta].nt=tot,ta=tot;
        tot++;
    }
    scanf("%s",ch+1);
    for(i=1;ch[i];i++)
    {
        e[tot].x=ch[i]-'a';
        if(!~hb)hb=tb=tot;
        else e[tb].nt=tot,tb=tot;
        tot++;
    }
    //cout<<ha<<" "<<ta<<" "<<hb<<" "<<tb<<endl;
    scanf("%d",&m);
    for(i=1;i<=m;i++)
    {
        int op;
        char str[2];
        scanf("%d",&op);
        q[i].op=op;
        if(op==5)continue;
        scanf("%s",str);
        e[tot].x=str[0]-'a';
        e[tot].id=i;
        if(op==1)
        {
            e[tot].nt=ha;
            ha=tot;
        }
        else if(op==2)
        {
            e[ta].nt=tot;
            ta=tot;
        }
        else if(op==3)
        {
            e[tot].nt=hb;
            hb=tot;
        }
        else if(op==4)
        {
            e[tb].nt=tot;
            tb=tot;
        }
        tot++;
    }
    tot=0;
    int sx,sy,ex,ey;
    sx=sy=-1;
    for(i=ha;;i=e[i].nt)
    {
        ch[++tot]=e[i].x;
        if(e[i].id)q[e[i].id].pos=tot;
        else {if(!~sx)sx=tot;ex=tot;}
        if(i==ta)break;
    }
    ch[++tot]=26;
    for(i=hb;;i=e[i].nt)
    {
        ch[++tot]=e[i].x;
        if(e[i].id)q[e[i].id].pos=tot;
        else {if(!~sy)sy=tot;ey=tot;}
        if(i==tb)break;
    }
    solve(tot,27);
    for(i=2;i<=tot;i++)p[i]=1+p[i>>1];
    for(i=0;1<<i<=tot;i++)
    {
        for(j=1;j+(1<<i)<=tot;j++)
        {
            if(!i)mi[i][j]=height[j];
            else mi[i][j]=min(mi[i-1][j],mi[i-1][j+(1<<(i-1))]);
        }
    }
    //cout<<sx<<" "<<ex<<" "<<sy<<" "<<ey<<endl;
    for(i=sx;i+ey-sy<=ex;i++)add(lev[i],1);
    for(i=1;i<=m;i++)
    {
        int op=q[i].op;
        if(op==1)
        {
            sx--;
            if(sx+ey-sy<=ex)add(lev[sx],1);
        }
        else if(op==2)
        {
            ex++;
            if(sx+ey-sy<=ex)add(lev[ex-ey+sy],1);
        }
        else if(op==3)
        {
            sy--;
            if(ex-ey+sy+1>=sx)add(lev[ex-ey+sy+1],-1);
        }
        else if(op==4)
        {
            ey++;
            if(ex-ey+sy+1>=sx)add(lev[ex-ey+sy+1],-1);
        }
        else
        {
            int pos=lev[sy],len=ey-sy+1;
            int l=1,r=pos-1,pl=pos,pr=pos;
            while(l<=r)
            {
                int mid=l+r>>1;
                if(ask(mid+1,pos)>=len)pl=mid,r=mid-1;
                else l=mid+1;
            }
            l=pos+1,r=tot;
            while(l<=r)
            {
                int mid=l+r>>1;
                if(ask(pos+1,mid)>=len)pr=mid,l=mid+1;
                else r=mid-1;
            }
            printf("%d\n",get(pr)-get(pl-1));
        }
    }
    return 0;
}
posted @ 2018-09-05 21:47  mxzf0213  阅读(209)  评论(0编辑  收藏  举报