HDU 4270 SAM 后缀自动机
来源:互联网 发布:消费金融 知乎 编辑:程序博客网 时间:2024/06/08 01:50
题目:给出一个串,有3种操作,
操作1:在原串后面,添加一个串
操作2:查询长度为len的子串或者长度小于等于len的后缀中字典序最小的
操作3:删除最后的len个字符
关于删除
首先明确一点: 新建的点只与模板点有关系
由新加入的点7产生的点8是根据点3为模板进行复制的(复制所有信息,包括位置)。那么点8是有点3控制的。
可以从两个图看出,删除点7,不删除点8也是可以达到第一个图的效果。
只是图不是最简的SAM。即a-a-b的父亲变为了a-b。但是无关大雅。
从这个可以看出新建立的辅助点是根据某点为模板,并且为这个模板分担了一些线路的点。
模板点控制这这些辅助点。当且仅当这个模板点被删除后,以这个模板点为模板扩展出去的辅助点才会也才能删除。
声明一个bool is_del[]
结构体里加上一个 bool *d 指针
字符串里的每一个结点对应一个域,即d=is_del[x],那么其复制出来的点也共享这个is_del[x]
当这个字符被删除后,也就是说这个域被删除后,所有的点的*d==0 ,全部删除了
删除从最后一个字符(域)开始删除,删除len个字符(域)即可
删除完之后last需要更新到删除后的第一个点
关于询问
node记录下该点的位置,如果这个状态是后缀,则ans=seq_cnt-i+1
否则为ans=p->pos-i+1
#include <iostream>#include <cstring>#include <cstdio>#include <string>using namespace std;const int maxn=200005;struct suffixautomaton{ struct node { int len,suf;//到这个状态允许的最大长长度,即max(s) node *f,*ch[26]; //如果suf==v_idx,则意味这个状态是后缀子串 bool *d; // int pos; //字符原来的位置 node(){} node(int l) { len=l; f=NULL; memset(ch,0,sizeof(ch)); } }; node *root,*last; node pool[maxn*2]; //储蓄结点用的 node *seq[maxn]; //用于储存输入进来的字符串,,其实就是储存pool数组中主心轴的点。 bool is_del[maxn*2]; //实际上is_del[i] 是代表第i个字符被删除没。node里的 *d是某一个is_del的地址,同一个域里的点共享一个is_del,同在一个域里面的点共享一个is_del[x]. int del_cnt,seq_cnt; //is_del数组的大小,seq数组的大小 int cnt; //结点的数量 int v_idx; //此处的v_idx方便设置suf,避免出错 void init() { v_idx=0; memset(is_del,0,sizeof(is_del)); del_cnt=seq_cnt=0; root=last=pool; seq[0]=root; //此处必须先设置第0位root,避免数组越界 memset(root,0,sizeof(node)); cnt=1; } node * new_node(int l=0) { node *x=pool+cnt++; memset(x,0,sizeof(node)); if(l!=0) x->len=l; return x; } void add(char ch) { int c=ch-'a'; node *p=last,*np=new_node(last->len+1); np->pos=np->len; np->d=is_del+del_cnt++; *np->d=0; seq[seq_cnt=np->len]=np; //以上四行初始化 last=np; for(;NULL!=p&&(NULL==p->ch[c]||*p->ch[c]->d);p=p->f) //如果这个点没有被删除且无下一个点ch p->ch[c]=np; if(NULL==p) np->f=root; else { if(p->ch[c]->len==p->len+1) np->f=p->ch[c]; else { //新建立的点是以p->ch[c]为模板复制的点,共享一个is_del[],当且仅当模板点被删除后新建立的点才会被删除。 node *q=p->ch[c],*nq=new_node(); *nq=*q; nq->len=p->len+1; q->f=np->f=nq; for(;NULL!=p&&p->ch[c]==q;p=p->f) p->ch[c]=nq; } } } void get_suf()//如果suf==v_idx,则意味这个状态是后缀子串 { v_idx++; node *p=last; while(p!=NULL) p->suf=v_idx,p=p->f; root->suf=0; } void del(int len) //从最后一个域开始删除 { while(len--) *seq[seq_cnt--]->d=1; last=seq[seq_cnt]; //last需要改变 } void query(int l) { get_suf(); node *p=root; for(int i=1;i<=l;i++) { for(int j=0;j<26;j++) if(!(NULL==p->ch[j]||*p->ch[j]->d)) { p=p->ch[j]; if(i==l) cout<<p->pos-i+1<<endl; else if(p->suf==v_idx) { cout<<seq_cnt-i+1<<endl; return ; } break; } } }};suffixautomaton sam;char str[maxn];int main(){ while(scanf("%s",str)!=EOF) { sam.init(); for(int i=0;str[i];i++) sam.add(str[i]); int q,cas,len; scanf("%d",&q); while(q--) { scanf("%d",&cas); if(cas==1) { scanf("%s",str); for(int i=0;str[i];i++) sam.add(str[i]); } else if(cas==2) { scanf("%d",&len); sam.query(len); } else { scanf("%d",&len); sam.del(len); } } } return 0;}
0 0
- HDU 4270 SAM 后缀自动机
- [SAM]后缀自动机
- 后缀自动机SAM
- Sam后缀自动机模板
- 后缀自动机SAM
- 后缀自动机SAM
- 后缀自动机(SAM)
- HDU 3518 Boring counting(后缀自动机 SAM)
- hdu 4416 Good Article Good sentence (后缀自动机 SAM)
- HDU 4436 str2int (后缀自动机SAM,多串建立)
- HDU 6208 ac自动机 hash sam 后缀数组
- spoj lcs2 后缀自动机SAM
- hdu4436 str2int 后缀自动机 SAM
- 后缀自动机(SAM)学习指南
- poj 3415 SAM后缀自动机
- 【后缀自动机sam学习小记】
- 后缀自动机(SAM)模板
- 【后缀自动机】【SAM】【自动机】【数据结构】后缀自动机理解(入门)
- hdu 2018 母牛的故事(简单dp)
- 从某个给定的字符串中选取需要的字符并组成字符串输出
- JSON net.sf.json
- 各种 unresolved external symbol 问题
- 算法2-8~2-11:链表的基本操作
- HDU 4270 SAM 后缀自动机
- 最重要的事
- Leetcode: Maximum Subarray
- 记忆化搜索或区间DP——石子合并
- Cocos2D-x特点
- (华中科大)江南雨烟 C++ STL 专栏
- 在Repeater中添加runat="server"的div,并控制其是否显示
- POJ 3255 (次短路)
- servlet+jsp数据库增删改查实例