• BZOJ 1396 识别子串 (后缀自动机+线段树)


    题目大意:

    给你一个字符串S,求关于每个位置x的识别串T的最短长度,T必须满足覆盖x,且T在S中仅出现一次

    神题

    以节点x为结尾的识别串,必须满足它在$parent$树的子树中只有一个$endpos$节点

    若令$fa=pre_{x},L=dep_{fa},R=dep_{x}$

    1.对于以$iin[1,R-L]$为开头,以$R$为结尾的串,合法串的长度是$R-i+1$

    如果在$S_{1...x}$串中不断删去开头的字符,删到串剩余长度为$dep_{fa}$时结束

    上述过程在$parent$树里的表现为,从表示串$S_{1...x}$的节点$a$,删掉最后一个字符后,跳到了表示$S_{x-dep_{fa}+1...x}$的节点$b$

    不必考虑$b$的$right$集合大小,因为$R$是递增的,如果$b$节点的串能作为识别串,$a$节点的答案一定不如$b$优秀

    所以我们干脆只讨论不跳到$b$的情况就行了

    那么$iin[1,R-L]$为开头,$R$为结尾的的串一定都能作为$[1,R-L]$的识别串

    2.对于以$iin[R-L+1,R]$为开头,以$R$为结尾的串,合法串的长度是$R-L+1$

    一样的道理,如果从$a$跳到了$b$,$b$节点的串可能不合法,但$a$节点的串一定合法

    那么以$L$为开头,$R$为结尾的的串一定都能作为$[1,R-L+1]$的识别串

    区间修改,单点查询,开两颗线段树维护一下就好

      1 #include <vector>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define N1 105000
      6 #define S1 (N1<<1)
      7 #define T1 (N1<<2)
      8 #define ll long long
      9 #define uint unsigned int
     10 #define rint register int 
     11 #define il inline 
     12 #define inf 0x3f3f3f3f
     13 #define idx(X) (X-'a')
     14 using namespace std;
     15 
     16 int gint()
     17 {
     18     int ret=0,fh=1;char c=getchar();
     19     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     20     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     21     return ret*fh;
     22 }
     23 char str[N1];
     24 int len;
     25 struct Seg{
     26 int mi[S1<<2];
     27 void pushdown(int rt){
     28     mi[rt<<1]=min(mi[rt<<1],mi[rt]);
     29     mi[rt<<1|1]=min(mi[rt<<1|1],mi[rt]);}
     30 void build(int l,int r,int rt)
     31 {
     32     mi[rt]=inf;
     33     if(l==r) return;
     34     int mid=(l+r)>>1;
     35     build(l,mid,rt<<1);
     36     build(mid+1,r,rt<<1|1);
     37 }
     38 void update(int L,int R,int l,int r,int rt,int w)
     39 {
     40     if(L<=l&&r<=R) {mi[rt]=min(w,mi[rt]);return;}
     41     pushdown(rt);int mid=(l+r)>>1;
     42     if(L<=mid) update(L,R,l,mid,rt<<1,w);
     43     if(R>mid) update(L,R,mid+1,r,rt<<1|1,w);
     44 }
     45 int query(int x,int l,int r,int rt)
     46 {
     47     if(l==r) return mi[rt];
     48     pushdown(rt);int mid=(l+r)>>1;
     49     if(x<=mid) return query(x,l,mid,rt<<1);
     50     else return query(x,mid+1,r,rt<<1|1);
     51 }
     52 }s1,s2;
     53 namespace SAM{
     54 int trs[S1][26],pre[S1],dep[S1],ed[S1],sz[S1],tot,la;
     55 void init(){tot=la=1;}
     56 void reduct(){la=1;}
     57 void insert(int c)
     58 {
     59     int p=la,np=++tot,q,nq;la=np;
     60     dep[np]=dep[p]+1;ed[np]=1;
     61     for(;p&&!trs[p][c];p=pre[p]) trs[p][c]=np;
     62     if(!p) {pre[np]=1;return;}
     63     q=trs[p][c];
     64     if(dep[q]==dep[p]+1) pre[np]=q;
     65     else{
     66         pre[nq=++tot]=pre[q];
     67         pre[q]=pre[np]=nq;
     68         dep[nq]=dep[p]+1;
     69         memcpy(trs[nq],trs[q],sizeof(trs[q]));
     70         for(;p&&trs[p][c]==q;p=pre[p]) trs[p][c]=nq;
     71     }
     72 }
     73 int hs[S1],que[S1],ans[N1];
     74 void solve()
     75 {
     76     for(int i=2;i<=tot;i++) hs[dep[i]]++;
     77     for(int i=1;i<=len;i++) hs[i]+=hs[i-1];
     78     for(int i=2;i<=tot;i++) que[hs[dep[i]]--]=i;
     79     int x,fx;
     80     for(int i=tot-1;i>0;i--)
     81     {
     82         x=que[i];
     83         sz[x]+=(ed[x]?1:0);
     84         sz[pre[x]]+=sz[x];
     85     }
     86     s1.build(1,tot,1);
     87     s2.build(1,tot,1);
     88     for(int i=2;i<=tot;i++)
     89     {
     90         x=que[i],fx=pre[x];
     91         if(sz[x]>1) continue;
     92         if(dep[fx]>=1) s1.update(dep[x]-dep[fx]+1,dep[x],1,tot,1,dep[fx]+1);
     93         if(dep[fx]+1<=dep[x]) s2.update(1,dep[x]-dep[fx],1,tot,1,dep[x]);
     94     }
     95     for(int i=1;i<=len;i++)
     96     {
     97         ans[i]=min(s1.query(i,1,tot,1),s2.query(i,1,tot,1)-i+1);
     98         printf("%d
    ",ans[i]);
     99     }
    100 }
    101 };
    102 
    103 int main()
    104 {
    105     //freopen("t2.in","r",stdin);
    106     scanf("%s",str+1);
    107     len=strlen(str+1);
    108     SAM::init();
    109     for(int i=1;i<=len;i++)
    110         SAM::insert(idx(str[i]));
    111     SAM::solve();
    112     return 0;
    113 }
  • 相关阅读:
    Jeecms3.x 常用标签使用总结
    MySQL的常用参数设置
    如何让iframe透明
    转载 张子阳 学习记录 c#网络编程
    Automate download of Realtime Trade and MarketDepth stocks demonstration
    c#2.0 锐利体验 视频链接 (李建忠老师主讲)
    转载 张子阳 学习记录 c#网络编程 5
    关于连接 providers 的一些代码 (学习QD)
    转载张子阳 学习记录 c#网络编程 4
    转载 张子阳 学习记录 c#网络编程
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10099204.html
Copyright © 2020-2023  润新知