bzoj1396: 识别子串

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 #define maxn 100005
  7 #define inf 100000000
  8 using namespace std;
  9 char st[maxn];
 10 int n,tot,last,root,sum[maxn<<1],tmp[maxn<<1],fa[maxn<<1],son[maxn<<1][26],dist[maxn<<1],ri[maxn<<1],pos[maxn<<1];
 11 struct Tsegment{
 12     void prepare(){tot=last=root=1,memset(ri,0,sizeof(ri));}
 13     int newnode(int x){
 14         dist[++tot]=x; return tot;
 15     }
 16     void add(int op,int x){
 17         int p=last,np=newnode(dist[p]+1); last=np; ri[np]=1; pos[np]=op;
 18         for (;p&&!son[p][x];p=fa[p]) son[p][x]=np;
 19         if (p==0) fa[np]=root;
 20         else{
 21             int q=son[p][x];
 22             if (dist[p]+1==dist[q]) fa[np]=q;
 23             else{
 24                 int nq=newnode(dist[p]+1);
 25                 memcpy(son[nq],son[q],sizeof(son[q]));
 26                 fa[nq]=fa[q],fa[q]=fa[np]=nq;
 27                 for (;p&&son[p][x]==q;p=fa[p]) son[p][x]=nq;
 28             }
 29         }
 30     }
 31 }SAM;
 32 struct Fsegment{
 33     int l,r,lazy,val;
 34 }tree1[maxn*8];
 35 struct date{
 36     void build(int k,int l,int r){
 37         tree1[k].lazy=tree1[k].val=inf; tree1[k].l=l,tree1[k].r=r;
 38         if (l==r) return;
 39         int mid=(l+r)/2;
 40         build(k*2,l,mid),build(k*2+1,mid+1,r);
 41     }
 42     void change(int k,int l,int r,int x,int y,int z){
 43         if (x>y) return;
 44         if (tree1[k].lazy!=inf){
 45             if (tree1[k*2].l) pushdown(k*2,tree1[k].lazy);
 46             if (tree1[k*2+1].l) pushdown(k*2+1,tree1[k].lazy);
 47             tree1[k].lazy=inf;
 48         }
 49         if (l>=x&&r<=y){
 50             pushdown(k,z);
 51             return;
 52         } int mid=(l+r)/2;
 53         if (x<=mid) change(k*2,l,mid,x,y,z);
 54         if (y>mid) change(k*2+1,mid+1,r,x,y,z);
 55     }
 56     void pushdown(int k,int x){
 57         tree1[k].lazy=min(tree1[k].lazy,x);
 58         if (tree1[k].l==tree1[k].r) tree1[k].val=min(tree1[k].val,tree1[k].lazy);
 59     }
 60     int query(int k,int l,int r,int x){
 61         if (tree1[k].lazy!=inf){
 62             if (tree1[k*2].l) pushdown(k*2,tree1[k].lazy);
 63             if (tree1[k*2+1].l) pushdown(k*2+1,tree1[k].lazy);
 64             tree1[k].lazy=inf;
 65         }
 66         if (l==r&&r==x) return tree1[k].val;
 67         int mid=(l+r)>>1,ans=inf;
 68         if (x<=mid) ans=min(ans,query(k*2,l,mid,x));
 69         else ans=min(ans,query(k*2+1,mid+1,r,x));
 70         return ans;
 71     }
 72 }Tree1;
 73 struct Ksegment{
 74     int l,r,val,lazy;
 75 }tree[maxn*8];
 76 struct Graph{
 77     void build(int k,int l,int r){
 78         tree[k].l=l,tree[k].r=r,tree[k].lazy=tree[k].val=inf;
 79         if (l==r) return; int mid=(l+r)/2;
 80         build(k*2,l,mid),build(k*2+1,mid+1,r);
 81     }
 82     void change(int k,int l,int r,int x,int y,int z){
 83         if (x>y) return;
 84         if (tree[k].lazy!=inf){
 85             if (tree[k*2].l) pushdown(k*2,tree[k].lazy);
 86             if (tree[k*2+1].l) pushdown(k*2+1,tree[k].lazy);
 87             tree[k].lazy=inf;
 88         }
 89         if (l>=x&&r<=y){
 90             pushdown(k,z);
 91             return;
 92         } int mid=(l+r)>>1;
 93         if (x<=mid) change(k*2,l,mid,x,y,z);
 94         if (y>mid) change(k*2+1,mid+1,r,x,y,z);
 95     }
 96     void pushdown(int k,int x){
 97         tree[k].lazy=min(tree[k].lazy,x);
 98         if (tree[k].l==tree[k].r) tree[k].val=min(tree[k].val,tree[k].lazy);
 99     }
100     int query(int k,int l,int r,int x){
101         if (tree[k].lazy!=inf){
102             if (tree[k*2].l) pushdown(k*2,tree[k].lazy);
103             if (tree[k*2+1].r) pushdown(k*2+1,tree[k].lazy);
104             tree[k].lazy=inf;
105         }
106         if (l==r&&r==x) return tree[k].val;
107         int mid=(l+r)>>1,ans=inf;
108         if (x<=mid) ans=min(ans,query(k*2,l,mid,x));
109         else ans=min(ans,query(k*2+1,mid+1,r,x));
110         return ans;
111     }
112 }Tree;
113 int main(){
114     scanf("%s",st+1),n=strlen(st+1);
115     SAM.prepare();
116     for (int i=1;i<=n;i++) SAM.add(i,st[i]-'a');
117     memset(sum,0,sizeof(sum));
118     for (int i=1;i<=tot;i++) sum[dist[i]]++;
119     for (int i=1;i<=tot;i++) sum[i]+=sum[i-1];
120     for (int i=1;i<=tot;i++) tmp[sum[dist[i]]--]=i;
121     for (int i=tot,x;i>=1;i--){
122         x=tmp[i];
123         if (fa[x]) ri[fa[x]]+=ri[x];
124     }
125     ri[root]=0;
126     Tree1.build(1,1,n);
127     Tree.build(1,1,n);
128     for (int i=1;i<=tot;i++){
129         if (ri[i]!=1) continue;
130         int x=pos[i],y=dist[i],z=dist[fa[i]]+1;
131         Tree1.change(1,1,n,x-y+1,x-z+1,x);   //第一棵线段树按位置,记得减
132         Tree.change(1,1,n,x-z+2,x,z);    //第二棵线段树按长度
133     }
134     for (int i=1;i<=n;i++){
135         printf("%d
",min(Tree1.query(1,1,n,i)-i+1,Tree.query(1,1,n,i)));
136     }
137     return 0;
138 }
139 
View Code

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1396

题目大意:

做法;看到题目中所说的T在S中只出现过一次,就很容易想到用后缀自动机嘛,显然就是right值为一的状态,而且right值为一的状态只能是每次add时第一个新建的点,这很显然嘛,这就很方便记录了。然后再用线段树维护一下最小值,稍微想一下就行,当时我竟然是很快就想到了,不过我inf开小了,狂WA不止。

后缀自动机+线段树。

原文地址:https://www.cnblogs.com/OYzx/p/5559473.html