Pty loves string 树上主席树,border,kmp Fail树

Posted 爷灬傲奈我何123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Pty loves string 树上主席树,border,kmp Fail树相关的知识,希望对你有一定的参考价值。

link
题意:
给定一个字符串,Q次询问,每次询问一个x,y,代表前后缀拼起来的字符串,询问该字符串在原串中的可重叠匹配次数。
Q<=2e5 n<=2e5
思路:
由于题目给的是[1,x] [n-y+1,n] ,如果匹配的话,那么就是匹配了[l,l+x-1],[r-y+1,r],且l+x==r-y+1,我们前后缀分开考虑,这里仅讨论前缀,对于某个前缀k,考虑在kmp的过程中,它一直通过fail指针暴跳,这里来复习一下fail指针,对于红色指针他他所对应的fail就是黑色指针,那么对于 a b a b abab abab这个串来说红色是能满足性质的,那么对于 a b ab ab这个串来说亦是如此。所以红色节点都在它们的子树中。
fail指针对应的下标就是对于以i结尾的字符串的最大相同前后缀,对于路径上的任意个点,他都是能满足[l,l+x-1]这一性质,那么就启发我们建图考虑,对于某个节点,他的子树中的每一个点都是能满足的。那么后缀也是如此,只需要倒着来维护。现在问题就变成了给你两棵树,并且两个id的子树,求两个子树中相同的节点的个数,现在我们已经建好了第一个树,那么主席树上的节点建立的是什么呢?主席树的下标是按照该树的dfs序建立的,他的节点就是对应的满足u+1的在第二个树上的dfs序,这样我们在查询的时候,只需要查询某个子树的主席树,并且dfs序在第二个子树r的范围内的所有对应节点就行了。复杂度 O ( l o g n ) . O(log n). O(logn).代码:

//#pragma GCC target("avx")
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast")
// created by myq 
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
#define x first
#define y second
typedef pair<int,int> pii;
const int N = 200010;
const int mod=998244353;
 struct node{
     int l;
     int r;
     int sum;
 }tr[N*40]; 
 int ne[N];
 int ne2[N];
 int idx;
 int dfn2[N];
 int dfn[N];
 int w[N];
 int w2[N];
 int cnt;
 int cnt2;
 vector<int>v[N],g[N];
 int sz[N],sz2[N];
 int root[N];
 int n;
 void insert(int p,int &q,int x,int l,int r)
 {
     q=++idx;
     tr[q].sum=0;
     tr[q]=tr[p];
     if(x<l || x>r)	return ;
     if(l==r)
     {
         tr[q].sum++;
         return ;
     }
    int mid=l+r>>1;
    if(x<=mid)
    insert(tr[p].l,tr[q].l,x,l,mid);
    else
    insert(tr[p].r,tr[q].r,x,mid+1,r);
    tr[q].sum=tr[tr[q].l].sum+tr[tr[q].r].sum;
 }
 int query(int p,int q,int l,int r,int ql,int qr)
 {
     if(l>=ql&&r<=qr)
         return tr[q].sum-tr[p].sum;
     int mid=l+r>>1;
     int res=0;
     if(ql<=mid)    res+=query(tr[p].l,tr[q].l,l,mid,ql,qr);
     if(qr>mid)    res+=query(tr[p].r,tr[q].r,mid+1,r,ql,qr);
     return res;
 }

 void dfs1(int u,int fa)
 {
     if(u)
     {
         dfn[u]=++cnt;
         w[cnt]=u;
     }
     sz[u]=1;
     for(auto j:v[u])
     {
         dfs1(j,u);
         sz[u]+=sz[j];
     }
 }
 void dfs2(int u)
 {
     // cout<<u<<"->";
     if(u)
     dfn2[u]=++cnt2;
     sz2[u]=1;
     for(auto j:g[u])
     {
         dfs2(j);
         sz2[u]+=sz2[j];
     }
 }
 
 char s[N];
 void solve()
 {
     int q;
     scanf("%d%d",&n,&q);
     scanf("%s",s+1);
     dfn2[n+1]=0;
     for(int i=1;i<=n;i++)    ne2[i]=n+1,ne[i]=0;
     for(int i=0;i<=n;i++)    v[i].clear(),g[i].clear();
     int j=0;
     for(int i=2;i<=n;i++)    
     {
         while(j&&s[j+1]!=s[i])    j=ne[j];
         if(s[j+1]==s[i])    j++;
         ne[i] =j;
     }
     j=n+1;
     
     for(int i=n-1;i>=1;i--)
     {
         while(j!=n+1&&s[j-1]!=s[i])        j=ne2[j];
         if(s[j-1]==s[i])    j--;
         ne2[i]=j;
     }
     for(int i=1;i<=n;i++)
     {
         v[ne[i]].push_back(i);
         // cout<<ne[i]<<" "<<i<<endl;
         if(ne2[i]==n+1)
         g[0].push_back(i);
         else
        {
        	// cout<<ne2[i]<<" "<<i<<endl;
        	g[ne2[i]].push_back(i);
        }
     }
     dfs2(0);
     dfs1(0,-1);
     for(int i=1;i<=n;i++)
     { 
	 	insert(root[i-1],root[i],dfn2[w[i]+1],1,n);
	 } 
     while(q--)
     {
         int l,r;
         scanf("%d%d",&l,&r);
         if(l+r>n)
         {
         	puts("0");
         	continue;
		 }
         r=n-r+1;
         printf("%d\\n",query(root[dfn[l]-1],root[dfn[l]+sz[l]-1],1,n,dfn2[r],dfn2[r]+sz2[r]-1));
     }
     
 }
int main() 
{ 
    int t;
    cin>>t;
    while(t--)
    {
        idx=0;
        cnt=0;
        cnt2=0;
        memset(tr,0,sizeof tr);
        solve();
    }
    return 0;
    
}
/**
* In every life we have some trouble
* When you worry you make it double
* Don't worry,be happy.
**/

以上是关于Pty loves string 树上主席树,border,kmp Fail树的主要内容,如果未能解决你的问题,请参考以下文章

2021牛客暑期多校训练营7 F.xay loves trees(主席树+树上尺取)

2021牛客暑期多校训练营7 F.xay loves trees 主席树+dfs序

牛客多校7.F.xay loves trees 主席树+dfs序

2021牛客多校7 - xay loves trees(dfs序+主席树-标记永久化)

xay loves trees(主席树dfs序 标记永久化优化)

BZOJ 2588 Spoj 10628 Count on a tree | 树上主席树