1. 程式人生 > 其它 >【題解】2021HDU多校第十場 HDU7084 Pty loves string

【題解】2021HDU多校第十場 HDU7084 Pty loves string

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\)

:節點\(i\)表示\(pre(i)\),對於\(i=1..n\),從\(f_i\)\(i\)連一條邊,表示\(border(pre(i))\rightarrow pre(i)\)。這樣,以節點\(u\)為根的子樹的節點所代表的的串均以\(pre(u)\)為字首。再對反串建\(border\ tree\),即以節點\(u\)為根的子樹的節點所代表的的串均以\(suf(u)\)為字首。一次詢問\(x,y\)相當於詢問有多少\(i\)滿足\(pre(i)\in suntree1(pre(x))\)\(suf(i+1)\in suntree2(suf(n-y+1))\)。可以轉化為二維數點問題,對第一顆樹上的每一個點\(u\)
,令其權值為\(dfn2[u+1]\)。查詢時,記\(y'=n-y+1\),相當於查詢\(pre(x)\)的子樹中有多少個點的權值在\([dfn2[y'],dfn2[y'+sz2[y']-1]]\)中。用主席樹按\(dfn\)序預處理即可。

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