【題解】2021HDU多校第十場 HDU7084 Pty loves string
阿新 • • 發佈:2021-08-19
2021HDU多校第十場 HDU7084 Pty loves string
題意
給一個長為\(n\)的串\(S\),共\(Q\)次詢問,每次詢問給定\(x,y\),求將\(S\)長為\(x\)的字首和長為\(y\)的字尾拼接得到的新串在\(S\)中出現了多少次。\(T\)組資料。
\(1\le T \le 5,1\le n,Q\le 2\times 10^5,1\le x,y\le n\)
題解
記\(pre(i):=S[1...i],suf(i):=S[i...n]\),首先用\(KMP\)求出\(S\)所有字首和所有後綴的\(border\),然後按照如下方式建立正串的\(border\ tree\)
#include <bits/stdc++.h> #define pb(x) emplace_back(x) using namespace std; const int N=2e5+10; char S[N]; int f[N],g[N],n,Q; int rt[N],gt=0,ls[N*40],rs[N*40],s[N*40]; #define mid ((l+r)>>1) void ins(int &o,int pre,int l,int r,int x){ o=++gt; s[o]=s[pre]+1;ls[o]=ls[pre];rs[o]=rs[pre]; if(l==r){return ;} if(x<=mid)ins(ls[o],ls[pre],l,mid,x); else ins(rs[o],rs[pre],mid+1,r,x); } int q(int o,int pre,int l,int r,int x,int y){ if(x<=l&&r<=y)return s[o]-s[pre]; int res=0; if(x<=mid)res+=q(ls[o],ls[pre],l,mid,x,y); if(y>mid)res+=q(rs[o],rs[pre],mid+1,r,x,y); return res; } vector<int> e[N],e2[N]; int sz[N],sz2[N],dfn[N],dfn2[N],c1=0,a[N]; void dfs(int u){ sz[u]=1;dfn[u]=++c1;a[c1]=u; for(auto v:e[u]){ dfs(v); sz[u]+=sz[v]; } } void dfs2(int u){ sz2[u]=1;dfn2[u]=++c1; for(auto v:e2[u]){ dfs2(v); sz2[u]+=sz2[v]; } } void f1(){ for(int i=1;i<=gt;i++){s[i]=ls[i]=rs[i]=0;} gt=0; scanf("%d%d%s",&n,&Q,S+1); int j=0; f[0]=0;g[n+1]=0; for(int i=2;i<=n;i++){ while(j&&S[j+1]!=S[i])j=f[j]; if(S[j+1]==S[i])++j; f[i]=j; } g[n]=n+1;j=n+1; for(int i=n-1;i>=1;i--){ while(j<n+1&&S[j-1]!=S[i])j=g[j]; if(S[j-1]==S[i])--j; g[i]=j; } for(int i=1;i<=n;i++){ e[f[i]].pb(i);e2[g[i]].pb(i); } c1=0;dfs(0); c1=0;dfs2(n+1); for(int i=1;i<=n+1;i++){ ins(rt[i],rt[i-1],1,n+1,dfn2[a[i]+1]); } while(Q--){ int x,y;scanf("%d%d",&x,&y);y=n-y+1; printf("%d\n",q(rt[dfn[x]+sz[x]-1],rt[dfn[x]-1],1,n+1,dfn2[y],dfn2[y]+sz2[y]-1)); } for(int i=0;i<=n+1;i++){e[i].clear();e2[i].clear();} } int main(){ int t;scanf("%d",&t); while(t--) f1(); return 0; }