zoukankan      html  css  js  c++  java
  • bzoj 2555 SubString(SAM+LCT)

    【题目链接】

        http://www.lydsy.com/JudgeOnline/problem.php?id=2555

    【题意】

        给定一个字符串,可以随时插入字符串,提供查询s在其中作为连续子串的出现次数。

    【思路】

        子串的出现次数,这使我们想到了后缀自动机,如果没有插入操作,则出现次数为字符串对应节点|right|集的大小。

        Right的递推方法为:|fa->right| <- |right|

        如果暴力做的话,可以每一次插入都重新计算right。时间复杂度为O(mn)。

      因为需要不断地插入字符串,所以parent树会发生变化,我们考虑使用LCT维护parent树。SAM中插入字符串时需要改变父亲,对应到LCT中即切断原树中本来的父亲,连接新的父亲,最后还应该把np的所有fa的|right|加1,对应于LCT中的一次区间加值。

        这样只需要用LCT维护一个值与一个懒标记即可。

     注意LCT原来的Link是连接两个点,而这里的Link需要切断原来的父亲后连接新父亲。

    【代码】

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #define FOR(a,b,c) for(int a=b;a<=c;a++)
      5 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
      6 using namespace std;
      7 
      8 const int N = 4e6+10;
      9 
     10 namespace LCT {
     11 
     12     struct Node {
     13         Node *ch[2],*fa;
     14         int v,add,rev;
     15         Node() ;
     16         void addv(int x) {
     17             v=v+x;
     18             add=add+x;
     19         }
     20         void reverse() {
     21             rev^=1;
     22             swap(ch[0],ch[1]);
     23         }
     24         void up_push() {
     25             if(fa->ch[0]==this||fa->ch[1]==this)
     26                 fa->up_push();
     27             if(add) {
     28                 ch[0]->addv(add);
     29                 ch[1]->addv(add);
     30                 add=0;
     31             }
     32             if(rev) {
     33                 ch[0]->reverse();
     34                 ch[1]->reverse();
     35                 rev=0;
     36             }
     37         }
     38         void maintain() {
     39         }
     40     } *null=new Node ;
     41     Node:: Node() {
     42         fa=ch[0]=ch[1]=null;
     43         add=v=rev=0;
     44     }
     45     
     46     void rot(Node* o,int d) {
     47         Node *p=o->fa;
     48         p->ch[d]=o->ch[d^1];
     49         o->ch[d^1]->fa=p;
     50         o->ch[d^1]=p;
     51         o->fa=p->fa;
     52         if(p==p->fa->ch[0])
     53             p->fa->ch[0]=o;
     54         else if(p==p->fa->ch[1])
     55             p->fa->ch[1]=o;
     56         p->fa=o;
     57         p->maintain();
     58     }
     59     void splay(Node* o) {
     60         o->up_push();
     61         Node *nf,*nff;
     62         while(o->fa->ch[0]==o||o->fa->ch[1]==o) {
     63             nf=o->fa,nff=nf->fa;
     64             if(o==nf->ch[0]) {
     65                 if(nf==nff->ch[0]) rot(nf,0);
     66                 rot(o,0);
     67             } else {
     68                 if(nf==nff->ch[1]) rot(nf,1);
     69                 rot(o,1);
     70             }
     71         }
     72         o->maintain();
     73     }
     74     void Access(Node* o) {
     75         Node* son=null;
     76         while(o!=null) {
     77             splay(o);
     78             o->ch[1]=son;
     79             o->maintain();
     80             son=o; o=o->fa;
     81         }
     82     }
     83     void evert(Node* o) {
     84         Access(o); 
     85         splay(o);
     86         o->reverse();
     87     }
     88     /*
     89     void Link(Node *u,Node *v) {
     90         evert(u);
     91         u->fa=v;
     92     }
     93     void Cut(Node *u,Node *v) {
     94         evert(u);
     95         Access(v); splay(v);
     96         u->fa=v->ch[0]=null;
     97         v->maintain();
     98     }
     99     */
    100     void Link(Node* u,Node* v) {    //改变父亲为v 需要切断原来的父亲 
    101         Access(u),splay(u);
    102         u->ch[0]->fa=u->ch[0]=null;
    103         u->fa=v;
    104     }
    105 
    106 }
    107 
    108 namespace SAM {
    109 
    110     struct Snode {
    111         Snode *ch[26],*fa;
    112         int l;
    113         LCT::Node *lct;
    114         Snode(int _=0) :fa(0x0),l(_) {
    115             memset(ch,0,sizeof(ch));
    116             lct=new LCT::Node;
    117         }
    118     } *root=new Snode,*last=root;
    119     
    120     void add(int x) {
    121         Snode *p=last,*np=new Snode(p->l+1);
    122         last=np;
    123         for(;p&&!p->ch[x];p=p->fa)
    124             p->ch[x]=np;        
    125         if(!p) {
    126             np->fa=root;
    127             LCT::Link(np->lct,root->lct);
    128         } else {
    129             Snode *q=p->ch[x];
    130             if(q->l==p->l+1) {
    131                 np->fa=q;
    132                 LCT::Link(np->lct,q->lct);
    133             } else {
    134                 Snode* nq=new Snode(p->l+1);
    135                 memcpy(nq->ch,q->ch,sizeof nq->ch);
    136                 nq->fa=q->fa;
    137                 LCT::Link(nq->lct,q->fa->lct);
    138                 np->fa=nq; q->fa=nq;
    139                 LCT::Link(q->lct,nq->lct);                    //修改parent树中的父亲 
    140                 LCT::Link(np->lct,nq->lct);
    141                 q->lct->up_push();
    142                 nq->lct->v=q->lct->v;
    143                 
    144                 for(;p&&p->ch[x]==q;p=p->fa)
    145                     p->ch[x]=nq;
    146             }
    147         }
    148         LCT::Access(np->lct);
    149         LCT::splay(np->lct);
    150         np->lct->addv(1);
    151     }
    152     void insert(char *s) {
    153         for(int i=0;s[i];i++)
    154             add(s[i]-'A');
    155     }
    156     int query(char *s) {
    157         for(Snode *p=root;p;p=p->ch[(*s++)-'A'])
    158             if(!*s) return p->lct->up_push(),p->lct->v;
    159         return 0;
    160     }
    161     
    162 }
    163 
    164 void Decode(char s[],int mask)
    165 {
    166     int i,n=strlen(s);
    167     for(int i=0;i<n;i++) {
    168         mask=(mask*131+i)%n;
    169         swap(s[i],s[mask]);
    170     }
    171 }
    172 
    173 int q,mask;
    174 char s[N],op[20];
    175 
    176 int main()
    177 {
    178     scanf("%d%s",&q,s);
    179     SAM::insert(s);
    180     while(q--) {
    181         scanf("%s%s",op,s);
    182         Decode(s,mask);
    183         if(op[0]=='Q') {
    184             int ans=SAM::query(s);
    185             mask^=ans;
    186             printf("%d
    ",ans);
    187         } else {
    188             SAM::insert(s);
    189         }
    190     }
    191     return 0;
    192 }
  • 相关阅读:
    近来无聊 写了一个google音乐的下载器
    HTML编辑器 HtmlArea
    Html编辑器 TinyMCE
    IE浏览器自定义地址协议 通过B/S程序中打开C/S程序
    html 元素的 onpropertychange 事件
    asp.net 服务器控件防止重复提交表单
    用 BindingSource 绑定窗体中控件不失去焦点无法更新数据源的问题
    动态创建大量 html dom 元素时提升性能
    很黄的日期格式化。。。
    Asp.net 导出 .html,.txt 等格式的文件
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5322904.html
Copyright © 2011-2022 走看看