【tmp】支持前后插入、删除的Pam

例题传送门(貌似是论文题来着qwq而且其实这题有更简洁的写法qwq)

论文传送门(130页左右)

#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;
			}
		}
	}
}

posted @ 2018-04-16 16:38  yoyoball  阅读(396)  评论(0)    收藏  举报