【HDU 6096】—String(扫描线+Trie)
考虑对正串和反串按照字典序排序
那么每次满足询问的前后缀的一定是分别是一段区间和
每个串正反串的位置是
那么每次询问就是有多少个
就变成平面上的问题了
扫描线就可以了
但是对于的情况会算错
对于每个询问枚举前后重叠了几个字符哈希判一下有几个就可以了
由于不知道重载了字典序大小
又算错了直接的复杂度
就写了个排字典序
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define pic pair<int,char>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
#define poly vector<int>
#define chemx(a,b) ((a)<(b)?(a)=(b):0)
#define chemn(a,b) ((a)>(b)?(a)=(b):0)
cs int N=100005,M=500005;
struct Trie{
int nxt[M][26],ed[M],val[M],mx[M],mn[M],tot,num;
inline void clear(){
for(int i=tot;~i;i--)mn[i]=mx[i]=0,val[i]=ed[i]=0,memset(nxt[i],0,sizeof(nxt[i]));
tot=num=0;
}
inline void insert(char *s,int id){
int p=0;
for(int i=1,len=strlen(s+1);i<=len;i++){
int c=s[i]-'a';
if(!nxt[p][c])nxt[p][c]=++tot,mn[tot]=1e9,mx[tot]=-1e9;
p=nxt[p][c];
}
ed[id]=p,val[p]=1;
}
void dfs(int u){
if(val[u])mx[u]=mn[u]=val[u]=++num;
for(int i=0;i<26;i++){
int v=nxt[u][i];
if(!v)continue;
dfs(v);
chemx(mx[u],mx[v]),chemn(mn[u],mn[v]);
}
}
inline void build(){
dfs(0);
}
inline pii query(char *s){
int p=0;
for(int i=1,len=strlen(s+1);i<=len;i++){
int c=s[i]-'a';
if(!nxt[p][c])return pii(1e9,-1e9);
p=nxt[p][c];
}
return pii(mn[p],mx[p]);
}
}tr1,tr2;
namespace Has{
int bas1=1331,mod1=1237876127,bas2=233,mod2=973912731;
int pw1[M],pw2[M],len1,len2;
int pre1[M],pre2[M],suf1[M],suf2[M];
map<pii,int> mp;
inline void init(){
pw1[0]=pw2[0]=1;
for(int i=1;i<M;i++)pw1[i]=1ll*pw1[i-1]*bas1%mod1,pw2[i]=1ll*pw2[i-1]*bas2%mod2;
}
inline void clear(){
mp.clear();
}
inline void insert(char *s){
int len=strlen(s+1);
int res1=0,res2=0;
for(int i=1;i<=len;i++){
int v=s[i]-'a'+1;
res1=(1ll*res1*bas1+v)%mod1,res2=(1ll*res2*bas2+v)%mod2;
}
mp[pii(res1,res2)]++;
}
inline bool check(int p){
return(((pre1[len1]-1ll*pre1[len1-p]*pw1[p])%mod1+mod1)%mod1==suf1[p]&&((pre2[len1]-1ll*pre2[len1-p]*pw2[p])%mod2+mod2)%mod2==suf2[p]);
}
inline int query(char *pre,char *suf){
len1=strlen(pre+1),len2=strlen(suf+1);
int anc=0;
for(int i=1;i<=len2;i++){
int v=suf[i]-'a'+1;
suf1[i]=(1ll*suf1[i-1]*bas1+v)%mod1,suf2[i]=(1ll*suf2[i-1]*bas2+v)%mod2;
}
for(int i=1;i<=len1;i++){
int v=pre[i]-'a'+1;
pre1[i]=(1ll*pre1[i-1]*bas1+v)%mod1,pre2[i]=(1ll*pre2[i-1]*bas2+v)%mod2;
}
for(int i=1;i<=min(len1,len2);i++)if(check(i)){
int h1=(1ll*pre1[len1-i]*pw1[len2]+suf1[len2])%mod1,h2=(1ll*pre2[len1-i]*pw2[len2]+suf2[len2])%mod2;
if(mp.count(pii(h1,h2)))anc+=mp[pii(h1,h2)];
}
return anc;
}
}
char s[M],t[M];
int n,m,ans[N];
vector<int> p[N];
struct ask{
int l,r,coef,id;
ask(int _l=0,int _r=0,int _c=0,int _i=0):l(_l),r(_r),coef(_c),id(_i){}
};
vector<ask> q[N];
namespace Seg{
int s[N<<2];
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
void build(int u,int l,int r){
s[u]=0;
if(l==r)return;
build(lc,l,mid),build(rc,mid+1,r);
}
void update(int u,int l,int r,int p){
if(l==r){s[u]++;return;}
if(p<=mid)update(lc,l,mid,p);
else update(rc,mid+1,r,p);
s[u]=s[lc]+s[rc];
}
int query(int u,int l,int r,int st,int des){
if(st<=l&&r<=des)return s[u];
int res=0;
if(st<=mid)res+=query(lc,l,mid,st,des);
if(mid<des)res+=query(rc,mid+1,r,st,des);
return res;
}
}
int main(){
int T=read();Has::init();
while(T--){
n=read(),m=read();
Has::clear();
tr1.clear(),tr2.clear();
Seg::build(1,1,n);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
int len=strlen(s+1);
tr1.insert(s,i);
Has::insert(s);
reverse(s+1,s+len+1);
tr2.insert(s,i);
}
tr1.build(),tr2.build();
for(int i=1;i<=n;i++){
int x=tr1.val[tr1.ed[i]],y=tr2.val[tr2.ed[i]];
p[x].pb(y);
// cout<<x<<" "<<y<<'\n';
}
for(int i=1;i<=m;i++){
scanf("%s",s+1);
pii now1=tr1.query(s);
scanf("%s",t+1);
int len=strlen(t+1);
ans[i]-=Has::query(s,t);
reverse(t+1,t+len+1);
pii now2=tr2.query(t);
if(now1.fi>now1.se||now2.fi>now2.se)continue;
q[now1.fi-1].pb(ask(now2.fi,now2.se,-1,i));
q[now1.se].pb(ask(now2.fi,now2.se,1,i));
}
for(int i=1;i<=n;i++){
for(int &x:p[i])Seg::update(1,1,n,x);
for(ask &x:q[i]){
ans[x.id]+=x.coef*Seg::query(1,1,n,x.l,x.r);
}
p[i].clear(),q[i].clear();
}
for(int i=1;i<=m;i++)cout<<ans[i]<<'\n',ans[i]=0;
}
}