• 【题解】2021HDU多校第十场 HDU7084 Pty loves string


    2021HDU多校第十场 HDU7084 Pty loves string

    题意

    给一个长为(n)的串(S),共(Q)次询问,每次询问给定(x,y),求将(S)长为(x)的前缀和长为(y)的后缀拼接得到的新串在(S)中出现了多少次。(T)组数据。

    (1le T le 5,1le n,Qle 2 imes 10^5,1le x,yle 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)) ightarrow pre(i))。这样,以节点(u)为根的子树的节点所代表的的串均以(pre(u))为前缀。再对反串建(border tree),即以节点(u)为根的子树的节点所代表的的串均以(suf(u))为前缀。一次询问(x,y)相当于询问有多少(i)满足(pre(i)in subtree1(pre(x)))(suf(i+1)in subtree2(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
    ",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;
    }
    
  • 相关阅读:
    powershell:clear-item
    windows-杂笔
    powershell:Clear-EventLog
    powershell:Get-ChildItem
    powershell 杂笔
    power-shell:clear-content
    powershell:checkpoint-computer
    vim-缩进设置
    powershell:move-item
    powershell:add-content
  • 原文地址:https://www.cnblogs.com/bobh/p/15163583.html
Copyright © 2020-2023  润新知