【tmp】支持前后插入、删除的Pam
例题传送门(貌似是论文题来着qwq而且其实这题有更简洁的写法qwq)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#define Pr pair<int,int>
#define mp make_pair
using namespace std;
const int MAXN=5*(1e4)+10,C=5,MOD=9260817,PAM=MAXN;
char str[MAXN];
int s[MAXN],ans[MAXN];
Pr st[MAXN];
vector<Pr> rec[MAXN];
int n,m,sq,top;
int block_id(int x){return (x-1)/sq;}
int change(char ch);
struct Q{/*{{{*/
int l,r,id;
Q(){}
Q(int _l,int _r,int _id){l=_l;r=_r;id=_id;}
friend bool operator < (Q x, Q y)
{return block_id(x.l)==block_id(y.l)?x.r<y.r:block_id(x.l)<block_id(y.l);}
}ask[MAXN];/*}}}*/
namespace Hs{/*{{{*/
struct data{
int l,r,val,nxt;
data(){}
data(int _l,int _r,int _val){l=_l;r=_r;val=_val;}
}cnt[12000000];
int h[MOD],tm[MOD];
int tot,now;
void init(){
++now;
tot=0;
}
int get_loc(int l,int r){
return 1LL*l*r%MOD*r%MOD;
}
bool add_cnt(int l,int r){
int id=get_loc(l,r);
if (tm[id]!=now) h[id]=-1,tm[id]=now;
for (int i=h[id];i!=-1;i=cnt[i].nxt)
if (cnt[i].l==l&&cnt[i].r==r){
++cnt[i].val;
return cnt[i].val==1;
}
cnt[++tot]=data(l,r,1); cnt[tot].nxt=h[id]; h[id]=tot;
return true;
}
bool del_cnt(int l,int r){
int id=get_loc(l,r);
if (tm[id]!=now) h[id]=-1,tm[id]=now;
for (int i=h[id];i!=-1;i=cnt[i].nxt)
if (cnt[i].l==l&&cnt[i].r==r){
--cnt[i].val;
if (cnt[i].val==0) return true;
return false;
}
return false;
}
}/*}}}*/
//quick[t][c]=t的最长的满足前驱为c的回文后缀
//imp[x]=该节点对应的子串s(l,r)是否满足:
// 1.回文 2.不存在l'<l满足s(l',r)回文 3.不存在r'>r满足s(l,r')回文
//child[x]=x在fail树上的儿子数
namespace Pam{/*{{{*/
int ch[PAM][C],len[PAM],suf[PAM],quick[PAM][C],pre[PAM];
int imp[PAM],child[PAM];
int tot,L,R,lens,sz;
void init_node(int x){
for (int i=0;i<C;++i) ch[x][i]=0,quick[x][i]=0;
suf[x]=0; len[x]=0; imp[x]=0; pre[x]=0; child[x]=0;
}
void init(){
for (int i=0;i<=1;++i) init_node(i);
for (int i=0;i<C;++i) quick[0][i]=1;
tot=1; L=R=0; suf[0]=1; len[0]=0; sz=0;
len[1]=-1; lens=0;
}
int find(int pos,int x,int op,int c){//op==-1->R, 1->L
if (len[x]==lens-1||str[pos+op*(len[x]+1)]!=str[pos])
x=quick[x][c];
return x;
}
int newnode(){
++sz;
init_node(++tot);
return tot;
}
void expand_R(int pos){//往右边插入一个字符
++lens;
int c=change(str[pos]),p=find(pos,R,-1,c),np=ch[p][c],q;
if (!ch[p][c]){
np=newnode();
q=suf[p];
len[np]=len[p]+2;
pre[np]=p;
if (p==1) suf[np]=0;
else suf[np]=ch[quick[p][c]][c];
++child[suf[np]];
memcpy(quick[np],quick[suf[np]],sizeof(quick[np]));
quick[np][change(str[pos-len[suf[np]]])]=suf[np];
ch[p][c]=np;
}
if (len[np]==lens) L=np;
if (suf[np]!=1)
if (Hs::add_cnt(pos-len[suf[np]]+1,pos))
--imp[suf[np]];
R=ch[p][c];
++imp[ch[p][c]];
}
void expand_L(int pos){//往左边插入一个字符
++lens;
int c=change(str[pos]),p=find(pos,L,1,c),np=ch[p][c],q;
if (!ch[p][c]){
np=newnode();
q=suf[p];
len[np]=len[p]+2;
pre[np]=p;
if (p==1) suf[np]=0;
else suf[np]=ch[quick[p][c]][c];
++child[suf[np]];
memcpy(quick[np],quick[suf[np]],sizeof(quick[np]));
quick[np][change(str[pos+len[suf[np]]])]=suf[np];
ch[p][c]=np;
}
if (len[np]==lens) R=np;
st[++top]=mp(ch[p][c],L);//st记录每次插入到哪个节点以及插入前的L值
L=ch[p][c];
++imp[ch[p][c]];
}
int who(int x){
for (int i=0;i<C;++i)
if (ch[pre[x]][i]==x) return i;
}
void del(int which,int pos,int preL){ //删除左边第一个字符(删除右边类似)
--lens;
if (suf[which]!=1)
if (Hs::del_cnt(pos,pos+len[suf[which]]-1))
++imp[suf[which]];
--imp[which];
if (!imp[which]&&!child[which]){
--child[suf[which]];
ch[pre[which]][who(which)]=0;
--sz;
}
L=preL;
}
};/*}}}*/
int solve_short(int l,int r);
int solve_long(int l,int r);
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
scanf("%s",str+1);
bool flag=true;
for (int i=1;i<=n&&flag;++i)
if (change(str[i])) flag=false;
int l,r,tmp;
if (flag){
for (int i=1;i<=m;++i){
scanf("%d%d",&l,&r);
printf("%d\n",r-l+1);
}
return 0;
}
sq=sqrt(n);
for (int i=1;i<=m;++i){
scanf("%d%d",&l,&r);
ask[i]=Q(l,r,i);
}
int debug;
sort(ask+1,ask+1+m);
for (int i=1;i<=m;++i){
if (block_id(ask[i].l)==block_id(ask[i].r))
ans[ask[i].id]=solve_short(ask[i].l,ask[i].r);
else{
tmp=i;
while (tmp<m&&block_id(ask[i].l)==block_id(ask[tmp+1].l)) ++tmp;
solve_long(i,tmp);
i=tmp;
}
}
//printf("%d\n",debug);
for (int i=1;i<=m;++i) printf("%d\n",ans[i]);
}
int change(char ch){
if (ch=='A') return 0;
if (ch=='G') return 1;
if (ch=='C') return 2;
if (ch=='T') return 3;
}
int solve_short(int l,int r){
Pam::init();Hs::init();
for (int i=l;i<=r;++i)
Pam::expand_R(i);
return Pam::sz;
}
int solve_long(int l,int r){
int pre_ed=(block_id(ask[l].l)+1)*sq,tmp;
Pam::init();
Hs::init();
for (int i=pre_ed+1;i<=n;++i) rec[i].clear();
for (int i=l;i<=r;++i)
rec[ask[i].r].push_back(mp(ask[i].l,ask[i].id));
top=0;
for (int i=pre_ed+1;i<=n;++i){
Pam::expand_R(i);
for (int j=0;j<rec[i].size();++j){
tmp=rec[i][j].first;
for (int k=pre_ed;k>=tmp;--k){
Pam::expand_L(k);
}
ans[rec[i][j].second]=Pam::sz;
for (int k=tmp;k<=pre_ed;++k){
Pam::del(st[top].first,k,st[top].second);
--top;
}
}
}
}