BZOJ 3881: [Coci2015]Divljak

Posted 北屿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3881: [Coci2015]Divljak相关的知识,希望对你有一定的参考价值。

Description

有两个集合\(ST\),\(S\)集合已知。
有两个操作
添加一个字符串到\(T\)
询问T中有多少\(S_i\)

\(n,q\leqslant 10^5,len(|S|),len(|T|)\leqslant 2\times 10^5\)

Solution

Trie树+DFS序.

添加一个字符串就要把Trie树上经过的节点及其fail树上的祖先+1
将他差分一下,每次询问出现次数就变成了询问子树和。
然后就是几条树梿的+1操作,因为差分过了,所以每个节点+1,相邻LCA-1

Code

/**************************************************************
    Problem: 3881
    User: BeiYu
    Language: C++
    Result: Accepted
    Time:16216 ms
    Memory:514652 kb
****************************************************************/
 
#include <bits/stdc++.h>
using namespace std;
 
const int N = 2000050;
const int M = 26;
 
namespace Bit {
    int d[N],n;
     
    void init(int x) { n=x; }
    void Add(int x,int v) { for(;x<=n;x+=x&-x) d[x]+=v; }
    int Qur(int x,int r=0) { for(;x;x-=x&-x) r+=d[x];return r; }
}
 
namespace Tree {
    vector<int> g[N];
    int cnt;
    int b[N],f[N][M],d[N],t1[N],t2[N];
     
    void AddEdge(int u,int v) { g[u].push_back(v),g[v].push_back(u); }
    void DFS(int rt) {
        stack<int> stk;
        stk.push(rt),f[rt][0]=rt,d[rt]=1;
        for(int x;!stk.empty();) {
            x=stk.top();
            if(b[x]) { t2[x]=cnt,stk.pop();continue; }
            b[x]=1,t1[x]=++cnt;
            for(int i=0,v;i<(int)g[x].size();i++) 
                if((v=g[x][i])!=f[x][0]) f[v][0]=x,d[v]=d[x]+1,stk.push(v);
        }
    }
    void init() {
        for(int j=1;j<M;j++) for(int i=1;i<=cnt;i++)
            f[i][j]=f[f[i][j-1]][j-1];
    }
    int LCA(int u,int v) {
        if(d[u]<d[v]) swap(u,v);
        int l=d[u]-d[v];
        if(l) for(int i=M-1;~i;i--) if(l&(1<<i)) u=f[u][i];
        if(u==v) return u;
        for(int i=M-1;~i;--i) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
        return f[u][0];
    }
};
 
 
namespace AC {
    int cnt,rt;
    int f[N],ch[N][M],ed[N];
     
    void init() { rt=cnt=0; }
    void insert(char* s,int id) {
        int l=strlen(s),x=rt;
        for(int i=0;i<l;i++) {
            int v=s[i]-‘a‘;
            if(!ch[x][v]) ch[x][v]=++cnt;
            x=ch[x][v];
        }ed[id]=x;
    }
    void Build() {
        queue<int> q;
        f[rt]=rt;
        for(int i=0;i<M;i++) if(ch[rt][i]) q.push(ch[rt][i]),f[ch[rt][i]]=rt;
        for(int x;!q.empty();) {
            x=q.front(),q.pop();
            for(int i=0;i<M;i++) {
                if(!ch[x][i]) { ch[x][i]=ch[f[x]][i];continue; }
                int v=ch[x][i];
                f[v]=ch[f[x]][i],q.push(v);
            }
        }
    }
    void get_f() {
        for(int i=1;i<=cnt;i++) Tree::AddEdge(i,f[i]);
        Tree::DFS(0);
        Tree::init();
         
//      for(int i=1;i<=cnt;i++) cout<<i<<" "<<f[i]<<endl;
//      for(int i=1;i<=cnt;i++) cout<<Tree::d[i]<<" ";cout<<endl;
//      for(int i=1;i<=cnt;i++) cout<<Tree::t1[i]<<" ";cout<<endl;
//      for(int i=1;i<=cnt;i++) cout<<Tree::t2[i]<<" ";cout<<endl;
    }
};
 
int cmp(int x,int y) { return Tree::t1[x]<Tree::t1[y]; }
vector<int> a;
void add_str(char* s) {
    int l=strlen(s),x=AC::rt;
    a.clear();
    for(int i=0;i<l;i++) {
        int v=s[i]-‘a‘;
        x=AC::ch[x][v];
        a.push_back(x);
    }
    sort(a.begin(),a.end(),cmp);
    x=a.size();
//  for(int i=0;i<x;i++) cout<<a[i]<<" ";cout<<endl;
    Bit::Add(Tree::t1[a[0]],1);
    for(int i=1;i<x;i++) {
        Bit::Add(Tree::t1[Tree::LCA(a[i],a[i-1])],-1);
        Bit::Add(Tree::t1[a[i]],1);
    }
}
 
int n,q;
char s[N];
 
int main() {
//  freopen("in.in","r",stdin);
    scanf("%d",&n);
    AC::init();
    for(int i=1;i<=n;i++) {
        scanf("%s",s);
        AC::insert(s,i);
    }
    AC::Build();
    AC::get_f();
    Bit::init(AC::cnt+1);
//  int oo,ooo;
//  while(cin>>oo>>ooo) cout<<Tree::LCA(oo,ooo)<<endl;
    scanf("%d",&q);
    for(int opt,x;q--;) {
        scanf("%d",&opt);
        if(opt==1) {
            scanf("%s",s);
            add_str(s);
        } else {
            scanf("%d",&x);
            printf("%d\n",Bit::Qur(Tree::t2[AC::ed[x]])-Bit::Qur(Tree::t1[AC::ed[x]]-1));
        }
    }return 0;
}

  

以上是关于BZOJ 3881: [Coci2015]Divljak的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 3881 [Coci2015]Divljak——LCT维护parent树链并

BZOJ3881 Coci2015 Divljak fail树+差分

bzoj3881[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组

[BZOJ3745][COCI2015]Norma(分治)

BZOJ3745[Coci2015]Norma cdq分治

BZOJ3743[Coci2015]Kamp 树形DP