zoukankan      html  css  js  c++  java
  • BZOJ2555:SubString(SAM,LCT)

    Description

    懒得写背景了,给你一个字符串init,要求你支持两个操作
    (1):在当前字符串的后面插入一个字符串
    (2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
    你必须在线支持这些操作。

    Input

    第一行一个数Q表示操作个数
    第二行一个字符串表示初始字符串init
    接下来Q行,每行2个字符串Type,Str
    Type是ADD的话表示在后面插入字符串。
    Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
    为了体现在线操作,你需要维护一个变量mask,初始值为0 

        

    读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
    询问的时候,对TrueStr询问后输出一行答案Result
    然后mask=maskxorResult
    插入的时候,将TrueStr插到当前字符串后面即可。
    HINT:ADD和QUERY操作的字符串都需要解压
    长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
    新加数据一组--2015.05.20

    Output

    Sample Input

    2
    A
    QUERY B
    ADD BBABBBBAAB

    Sample Output

    0

    Solution

    可以发现这个题如果不是多组询问的话,就是求SAM的right集合的大小的裸题
    不过一边插入一边询问很显然是无法像原来一样等全部字符都插入后再排序求right集合大小的
    不过根据right集合的定义,其实我们可以发现一个点的right集合大小就是子树的np节点的个数
    这玩意儿只需要用LCT维护子树权值和就好了

    Code

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #define N (1200000+1000)
      5 using namespace std;
      6 
      7 int Father[N],Son[N][2],Size[N],Si[N],Rev[N],R[N],T,mask;
      8 char s[N],opt[10];
      9 
     10 int Get(int x){return Son[Father[x]][1]==x;}
     11 int Is_root(int x){return Son[Father[x]][0]!=x && Son[Father[x]][1]!=x;}
     12 void Update(int x){Size[x]=Si[x]+Size[Son[x][0]]+Size[Son[x][1]]+R[x];}
     13 
     14 void Pushdown(int x)
     15 {
     16     if (x && Rev[x])
     17     {
     18         if (Son[x][0]) Rev[Son[x][0]]^=1;
     19         if (Son[x][1]) Rev[Son[x][1]]^=1;
     20         swap(Son[x][0],Son[x][1]);
     21         Rev[x]=0;
     22     }
     23 }
     24 
     25 void Rotate(int x)
     26 {
     27     int wh=Get(x);
     28     int fa=Father[x],fafa=Father[fa];
     29     if (!Is_root(fa)) Son[fafa][Son[fafa][1]==fa]=x;
     30     Son[fa][wh]=Son[x][wh^1]; Father[fa]=x;
     31     Son[x][wh^1]=fa; Father[x]=fafa;
     32     if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
     33     Update(fa); Update(x);
     34 }
     35 
     36 void Push(int x){if (!Is_root(x)) Push(Father[x]); Pushdown(x);}
     37 void Splay(int x)
     38 {
     39     Push(x);
     40     for (int fa; !Is_root(x); Rotate(x))
     41         if (!Is_root(fa=Father[x]))
     42             Rotate(Get(fa)==Get(x)?fa:x);
     43 }
     44 
     45 void Access(int x)
     46 {
     47     for (int y=0; x; y=x,x=Father[x])
     48     {
     49         Splay(x);
     50         Si[x]+=Size[Son[x][1]]; Si[x]-=Size[y];
     51         Son[x][1]=y; Update(x);
     52     }
     53 }
     54 
     55 void Make_root(int x){Access(x); Splay(x); Rev[x]^=1;}
     56 int Find_root(int x){Access(x); Splay(x); while (Son[x][0]) x=Son[x][0]; return x;}
     57 void Link(int x,int y){Make_root(x); Make_root(y); Father[x]=y; Si[y]+=Size[x]; Update(y);}
     58 void Cut(int x,int y){Make_root(x); Access(y); Splay(y); Son[y][0]=Father[x]=0; Update(y);}
     59 
     60 struct SAM
     61 {
     62     int fa[N],son[N][28],step[N];
     63     int p,q,np,nq,last,cnt;
     64     SAM(){last=++cnt;}
     65     
     66     void Insert(int x)
     67     {
     68         p=last; np=last=++cnt; step[np]=step[p]+1; R[np]=1; 
     69         while (p && !son[p][x]) son[p][x]=np,p=fa[p];
     70         if (!p) fa[np]=1,Link(np,1);
     71         else
     72         {
     73             q=son[p][x];
     74             if (step[p]+1==step[q]) fa[np]=q,Link(np,q);
     75             else
     76             {
     77                 nq=++cnt; step[nq]=step[p]+1;
     78                 memcpy(son[nq],son[q],sizeof(son[q]));
     79                 Link(nq,fa[q]); Cut(q,fa[q]); Link(q,nq); Link(np,nq); 
     80                 fa[nq]=fa[q]; fa[q]=fa[np]=nq;
     81                 while (son[p][x]==q) son[p][x]=nq,p=fa[p];
     82             }
     83         }
     84     }
     85     int Query(char s[])
     86     {
     87         Make_root(1);
     88         int now=1, len=strlen(s);
     89         for (int i=0; i<len; ++i)
     90             if (son[now][s[i]-'A']) now=son[now][s[i]-'A'];
     91             else return 0;
     92         Access(now); Splay(now);
     93         return Size[now]-Size[Son[now][0]];
     94     }
     95 }SAM;
     96 
     97 void Decode(char *s,int mask)
     98 {
     99     int len=strlen(s);
    100     for(int i=0; i<len; ++i)
    101     {
    102         mask=(mask*131+i)%len;
    103         swap(s[i],s[mask]);
    104     }
    105 }
    106 
    107 int main()
    108 {
    109     scanf("%d",&T);
    110     scanf("%s",s);
    111     int len=strlen(s);
    112     for (int i=0; i<len; ++i)
    113         SAM.Insert(s[i]-'A');
    114     while (T--)
    115     {
    116         scanf("%s%s",opt,s);
    117         int len=strlen(s);
    118         Decode(s,mask);
    119         if (opt[0]=='A')
    120             for (int i=0; i<len; ++i)
    121                 SAM.Insert(s[i]-'A');
    122         else
    123         {
    124             int ans=SAM.Query(s);
    125             printf("%d
    ",ans);
    126             mask^=ans;
    127         }
    128     }
    129 }
  • 相关阅读:
    keras 报错 ValueError: Tensor conversion requested dtype int32 for Tensor with dtype float32: 'Tensor("embedding_1/random_uniform:0", shape=(5001, 128), dtype=float32)'
    redis 安装启动及设置密码<windows>
    mysql配置主从数据库
    将已有的项目提交到GitHub
    Top 5 SSH Clients for Windows (Alternatives of PuTTY)
    jQuery 插件写法示例
    Spring 定时操作业务需求
    eclipse 修改js文件无法编译到项目中
    linux 目录结构图解
    MongoDB 概念解析
  • 原文地址:https://www.cnblogs.com/refun/p/9378216.html
Copyright © 2011-2022 走看看