zoukankan      html  css  js  c++  java
  • [NOI2018]你的名字(SAM+线段树合并)

    考虑l=1,r=n的68分,对S和T建SAM,对T的SAM上的每个节点,计算它能给答案带来多少贡献。

    T上节点x代表的本质不同的子串数为mx[x]-mx[fa[x]],然后需要去掉所代表子串与S的最长公共子串的长度。

    从1到length(T)扫一遍,SAM基本操作求出每个前缀与S的最长公共子串。

    答案为$sum_{i=1}^{cnt}max(0,mx[x]-max(mx[fa[x]],len[tag[x]]))$,其中tag[x]是x所代表的子串在T中的第一个出现位置,len[i]为T的前缀i与S的最长公共子串。

    再考虑l,r任意的情况,唯一区别在于求某前缀与S的最长公共子串时,需要满足[l,r]的限制。

    即若想判断当前公共子串长是否可以为len,那么当前走到的点的parent树的子树内必须存在一个串的Right在[l+len,r]中。

    “某子树内是否存在[l+len,r]中的值”显然可以用主席树做,或可持久化线段树合并。

    下面大概证一下线段树合并的时空复杂度:

    1.由于每次合并时,若发现x与y的当前子树有一个为空则退出。这种情况每个节点最多会出现一次(合并之后这个位置就不再为空了),故这部分复杂度为$O(nlog n)$。

    2.除去情况一,则x与y合并的复杂度为两个树的重合节点个数。最坏情况发生在依次将一个个只有一个节点的树合并进来,这部分显然仍然是$O(nlog n)$的。

    3.不可持久化的线段树合并并不产生新节点,故空间复杂度为初始插入n个点的复杂度:$O(nlog n)$

    4.可持久化的线段树,根据算法流程容易发现时空复杂度同阶,于是复杂度也为$O(nlog n)$

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define lson ls[x],L,mid
     5 #define rson rs[x],mid+1,R
     6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     7 typedef long long ll;
     8 using namespace std;
     9 
    10 const int N=2000010,M=40000010;
    11 char s[N],t[N];
    12 int n,m,nd,Q,l,r,len[N],rt[N],id[N],ls[M],rs[M];
    13 
    14 struct SAM{
    15     int nd,lst,mx[N],fa[N],pos[N],son[N][27];
    16     
    17     void init(){
    18         nd=1; lst=1;
    19         rep(i,0,m*2) fa[i]=mx[i]=0;
    20         rep(i,0,m*2) rep(j,0,26) son[i][j]=0;
    21     }
    22     
    23     void ext(int c,int x){
    24         int p=lst,np=lst=++nd; pos[np]=x; mx[np]=mx[p]+1;
    25         while (p && !son[p][c]) son[p][c]=np,p=fa[p];
    26         if (!p) fa[np]=1;
    27         else{
    28             int q=son[p][c];
    29             if (mx[q]==mx[p]+1) fa[np]=q;
    30             else{
    31                 int nq=++nd; pos[nq]=pos[q]; mx[nq]=mx[p]+1;
    32                 memcpy(son[nq],son[q],sizeof(son[q]));
    33                 fa[nq]=fa[q]; fa[q]=fa[np]=nq;
    34                 while (p && son[p][c]==q) son[p][c]=nq,p=fa[p];
    35             }
    36         }
    37     }
    38     
    39 }S,T;
    40 
    41 bool cmp(int a,int b){ return S.mx[a]<S.mx[b]; }
    42 
    43 void ins(int &x,int L,int R,int k){
    44     if (!x) x=++nd;
    45     if (L==R) return;
    46     int mid=(L+R)>>1;
    47     if (k<=mid) ins(lson,k); else ins(rson,k);
    48 }
    49 
    50 bool que(int x,int L,int R,int l,int r){
    51     if (!x) return 0;
    52     if (L==l && r==R) return 1;
    53     int mid=(L+R)>>1;
    54     if (r<=mid) return que(lson,l,r);
    55     else if (l>mid) return que(rson,l,r);
    56         else return que(lson,l,mid)|que(rson,mid+1,r);
    57 }
    58 
    59 int merge(int x,int y){
    60     if (!x || !y) return x|y;
    61     int now=++nd;
    62     ls[now]=merge(ls[x],ls[y]);
    63     rs[now]=merge(rs[x],rs[y]);
    64     return now;
    65 }
    66 
    67 int main(){
    68     freopen("name.in","r",stdin);
    69     freopen("name.out","w",stdout);
    70     scanf("%s",s+1); n=strlen(s+1);
    71     S.init(); rep(i,1,n) S.ext(s[i]-'a',i),ins(rt[S.lst],1,n,i);
    72     rep(i,1,S.nd) id[i]=i;
    73     sort(id+1,id+S.nd+1,cmp);
    74     for (int i=S.nd; i>1; i--) rt[S.fa[id[i]]]=merge(rt[S.fa[id[i]]],rt[id[i]]);
    75     for (scanf("%d",&Q); Q--; ){
    76         scanf("%s%d%d",t+1,&l,&r); m=strlen(t+1);
    77         int now=0,x=1;
    78         T.init(); rep(i,1,m) T.ext(t[i]-'a',i);
    79         rep(i,1,m){
    80             int c=t[i]-'a';
    81             while (1){
    82                 if (!que(rt[S.son[x][c]],1,n,l+now,r)){
    83                     if (!now) break; now--;
    84                     if (now==S.mx[S.fa[x]]) x=S.fa[x];
    85                 }else{ now++; x=S.son[x][c]; break; }
    86             }
    87             len[i]=now;
    88         }
    89         ll ans=0;
    90         rep(i,2,T.nd) ans+=max(0,T.mx[i]-max(T.mx[T.fa[i]],len[T.pos[i]]));
    91         printf("%lld
    ",ans);
    92     }
    93     return 0;
    94 }
  • 相关阅读:
    《Microsoft Sql server 2008 Internals》读书笔记第十一章DBCC Internals(2)
    《Microsoft Sql server 2008 Internals》读书笔记第十一章DBCC Internals(9)
    《Microsoft Sql server 2008 Internals》读书笔记第九章Plan Caching and Recompilation(10)
    CKEditor在asp.net环境下的使用一例
    《Microsoft Sql server 2008 Internals》读书笔记第五章Table(7)
    《Microsoft Sql server 2008 Internals》读书笔记第九章Plan Caching and Recompilation(11)
    千万数据的连续ID表,快速读取其中指定的某1000条数据?
    javascript中的float运算精度
    .Net与Java的互操作(.NET StockTrader微软官方示例应用程序)
    《Microsoft Sql server 2008 Internals》读书笔记第十一章DBCC Internals(6)
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10229780.html
Copyright © 2011-2022 走看看