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\n",min(Tree1.query(1,1,n,i)-i+1,Tree.query(1,1,n,i))); 136 } 137 return 0; 138 } 139
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1396
题目大意:
做法;看到题目中所说的T在S中只出现过一次,就很容易想到用后缀自动机嘛,显然就是right值为一的状态,而且right值为一的状态只能是每次add时第一个新建的点,这很显然嘛,这就很方便记录了。然后再用线段树维护一下最小值,稍微想一下就行,当时我竟然是很快就想到了,不过我inf开小了,狂WA不止。
后缀自动机+线段树。