思路:
網上的題解有AC自動機的,有trie樹的,還有(亂搞?)的
首先把輸入的那n個串按照字典序排序,
把n個串翻轉以後再按照字典序排序
這樣我們發現, 查的前綴在字典序排序後是一段區間,
查的後綴翻轉一下在翻轉後的字典序排序以後也是一段區間
這樣如果不考慮重疊的問題,就是一個簡單的二維數點問題,一維排序,一維線段樹即可解決
如果有重疊的問題,我們需要搞出來每個字符串的長度,使給出的前綴長+後綴長>=原字符串長度
此時題目變成了三維偏序,排序後樹套樹即可。
//By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=500050; int cases,n,q,root[N<<3],cnt,tree[N*150],lson[N*150],rson[N*150]; struct Node{string str;int id,len;}X[N],Y[N],tmp; bool operator<(Node a,Node b){return a.str<b.str;} struct Pnt{int x,y,z;}p[N]; struct Ask{int xl,xr,yl,yr,z,id,ans;}ask[N]; bool cmp1(Pnt a,Pnt b){return a.z>b.z;} bool cmp2(Ask a,Ask b){return a.z>b.z;} bool cmp3(Ask a,Ask b){return a.id<b.id;} void Insert(int l,int r,int &pos,int wei){ if(!pos)pos=++cnt;tree[pos]++; if(l==r)return; int mid=(l+r)>>1; if(mid>=wei)Insert(l,mid,lson[pos],wei); else Insert(mid+1,r,rson[pos],wei); } void insert(int l,int r,int pos,int num,int wei){ Insert(1,n,root[pos],wei); if(l==r)return; int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; if(mid<num)insert(mid+1,r,rson,num,wei); else insert(l,mid,lson,num,wei); } int Query(int l,int r,int pos,int L,int R){ if(l>=L&&r<=R)return tree[pos]; int mid=(l+r)>>1; if(mid<L)return Query(mid+1,r,rson[pos],L,R); else if(mid>=R)return Query(l,mid,lson[pos],L,R); else return Query(l,mid,lson[pos],L,R)+Query(mid+1,r,rson[pos],L,R); } int query(int l,int r,int pos,int xl,int xr,int yl,int yr){ if(l>=xl&&r<=xr)return Query(1,n,root[pos],yl,yr); int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; if(mid<xl)return query(mid+1,r,rson,xl,xr,yl,yr); else if(mid>=xr)return query(l,mid,lson,xl,xr,yl,yr); else return query(l,mid,lson,xl,xr,yl,yr)+query(mid+1,r,rson,xl,xr,yl,yr); } int main(){ ios::sync_with_stdio(false); cin>>cases; while(cases--){ memset(tree,0,sizeof(int)*(cnt+5)); memset(lson,0,sizeof(int)*(cnt+5)); memset(rson,0,sizeof(int)*(cnt+5)); memset(root,0,sizeof(root));cnt=0; cin>>n>>q; for(int i=1;i<=n;i++)cin>>X[i].str; sort(X+1,X+1+n); for(int i=1;i<=n;i++)X[i].id=i,X[i].len=X[i].str.length(); for(int i=1;i<=n;i++)Y[i]=X[i]; for(int i=1;i<=n;i++)reverse(Y[i].str.begin(),Y[i].str.end()); sort(Y+1,Y+1+n); for(int i=1;i<=n;i++)p[i].x=Y[i].id,p[i].y=i,p[i].z=Y[i].len; for(int i=1;i<=q;i++){ string pre,suf;cin>>pre>>suf; ask[i].id=i;tmp.str=pre; ask[i].xl=lower_bound(X+1,X+1+n,tmp)-X; tmp.str=pre,tmp.str.push_back('z'+1); ask[i].xr=lower_bound(X+1,X+1+n,tmp)-X-1; tmp.str=suf,reverse(tmp.str.begin(),tmp.str.end()); ask[i].yl=lower_bound(Y+1,Y+1+n,tmp)-Y; tmp.str.push_back('z'+1); ask[i].yr=lower_bound(Y+1,Y+1+n,tmp)-Y-1; ask[i].z=pre.size()+suf.size(); } sort(p+1,p+1+n,cmp1);sort(ask+1,ask+1+q,cmp2); int tt=1; for(int i=1;i<=q;i++){ while(p[tt].z>=ask[i].z&&tt<=n)insert(1,n,1,p[tt].x,p[tt].y),tt++; if(ask[i].xl>ask[i].xr||ask[i].yl>ask[i].yr){ask[i].ans=0;continue;} ask[i].ans=query(1,n,1,ask[i].xl,ask[i].xr,ask[i].yl,ask[i].yr); }sort(ask+1,ask+1+q,cmp3); for(int i=1;i<=q;i++)cout<<ask[i].ans<<endl; } }