题意:
给出n个字符串和m个询问;
每个询问有l,r和一个字符串;
查询[l,r]区间中的所有是询问字符串的子串的最大长度;
n<=100000,m<=100000,字符串总长度<=500000;
此题为CH【弱省胡策】 #1 T2;
题解:
一道好题,感觉正解说起来只是一句话但是真是很有道理。。
就是说:将询问拆成log个区间,对线段树每个结点建AC自动机分别处理;
这样每个询问都只询问了log个区间,每个字符串也只被log个结点覆盖;
时间复杂度O(nlogn*26),代码极其好写。。
实际上这样也就是处理区间问题的基本方法之一,拆分成log个区间来做,用线段树一样的分析来保证复杂度;
不要忘了取模哦XD
代码:
#include<queue> #include<vector> #include<stdio.h> #include<string.h> #include<algorithm> #define N 110000 #define LEN 610000 #define S 26 #define lson l,mid,no<<1 #define rson mid+1,r,no<<1|1 #define vec vector<int> #define iter vec::iterator using namespace std; char buf1[LEN]; char* str[N]; char buf2[LEN]; char* p[N]; int L[N],R[N]; int ans[N]; vec query[N<<2]; int next[LEN][S],fail[LEN],len[LEN],tot; queue<int>q; int newnode() { int ret=++tot; memset(next[ret],0,sizeof(int)*S); fail[ret]=len[ret]=0; return ret; } void init() { tot=0; newnode(); } void Insert(char* s) { int p=1,index,l=0; while(*s!='\0') { index=*s-'a'; if(!next[p][index]) next[p][index]=newnode(); p=next[p][index]; s++; l++; } len[p]=max(len[p],l); } void Build() { int x,i,temp,p; q.push(1); while(!q.empty()) { x=q.front(),q.pop(); for(i=0;i<S;i++) { if(next[x][i]) { p=next[x][i]; temp=fail[x]; while(temp&&next[temp][i]==0) temp=fail[temp]; if(temp) fail[p]=next[temp][i],len[p]=max(len[fail[p]],len[p]); else fail[p]=1; q.push(p); } else { temp=fail[x]; while(temp&&next[temp][i]==0) temp=fail[temp]; if(temp) next[x][i]=next[temp][i]; else next[x][i]=1; } } } } int calc(char* s) { int p=1,ret=0; while(*s!='\0') { p=next[p][*s-'a']; ret=max(ret,len[p]); s++; } return ret; } void update(int l,int r,int no,int st,int en,int val) { if(st<=l&&r<=en) query[no].push_back(val); else { int mid=l+r>>1; if(en<=mid) update(lson,st,en,val); else if(st>mid) update(rson,st,en,val); else update(lson,st,en,val),update(rson,st,en,val); } } void slove(int l,int r,int no) { if(!query[no].empty()) { init(); for(int i=l;i<=r;i++) Insert(str[i]); Build(); for(iter it=query[no].begin();it!=query[no].end();it++) ans[*it]=max(calc(p[*it]),ans[*it]); } if(l==r) return ; int mid=l+r>>1; slove(lson); slove(rson); } int main() { int n,m,i,j,k,x,y; scanf("%d%d",&n,&m); str[0]=buf1,p[0]=buf2; for(i=1;i<=n;i++) { str[i]=str[i-1]+strlen(str[i-1])+1; scanf("%s",str[i]); } for(i=1;i<=m;i++) { p[i]=p[i-1]+strlen(p[i-1])+1; scanf("%d%d%s",L+i,R+i,p[i]); update(1,n,1,L[i],R[i],i); } slove(1,n,1); for(i=1;i<=m;i++) printf("%d\n",ans[i]%998244353);//千万别忘了取模!!!! return 0; }