アリのタイプライターBZOJ 2434(ACオートマトン+ +フェンウィックツリーシーケンスDFS)

問題の意味

あなたにいくつかの文字列を与え、そしていくつかは尋ねた
回数のy番目の文字列に登場あなたのx番目の文字列を依頼します

考え

AC自動機組み込み、これらの文字列
の性質に応じて、ツリーに失敗:Xノードである場合、任意のノードtにトライのルートは、ツリーの祖先に失敗し、XはYのサブストリングでなければならない
数及びXはYで発生xのサブツリーのルートノードのためにトライ木のルートノードyどのように多くのノードツリー、失敗する
最初の取り調べオフライン
これはノード建て交流自動機の問題であることからするので、我々はこのパスを構築することができますルートノードへの電流経路を維持するために
正しい経路上の点が1、および0である
我々は、ツリーとxのクエリケースサブツリーを失敗、クエリがYに到達するたびに、これは事前に失敗することができフェンウィックツリーのメンテナンスとDFSツリーシーケンス

あなたはこの質問の特殊性を除外する場合は、答えがトライをトラバースの方法によって更新されなければならない
作業の過程でトライを変え、失敗するので、

else trie[now][i]=trie[fail[now]][i];

時々ポイント前トライノードを作成するときにBFS構造は、高さより小さなノード(INトライ)である、ポインタ失敗
DFSのみ書き込みする必要があるので

void dfs(int x){
    //printf("==%d\n",x);
    add(bg[x],1);
    for(int i = 0; i < (int)Q[x].size(); i++){
        int y = Q[x][i].fst;
        ans[Q[x][i].sc]=sum(ed[y])-sum(bg[y]-1);
    }
    for(int i = 0; i < 26; i++){
        int y = ac.trie[x][i];
        if(!y||h[y]<=h[x])continue;
        dfs(y);
    }
    add(bg[x],-1);
}

コード

バージョン

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
    
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 3e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);

vector<int>v[maxn];
int id[maxn];
struct AC{
    //局部变量没有默认0!
    int trie[maxn][26];
    int num[maxn];//单词出现次数
    int fail[maxn],fa[maxn];
    int vis[maxn];//ask函数用到
    int tot,rt;
    int ntot;
    //多测可写个init
    void init(){tot=0;mem(vis,0);mem(trie,0);rt=0;ntot=0;}
    void add(char c){
        if(c=='P'){
            num[rt]++;
            id[++ntot]=rt;
            return;
        }
        if(c=='B'){
            rt=fa[rt];
            return;
        }
        int x = c-'a';
        if(!trie[rt][x]){
            trie[rt][x]=++tot;
            fa[tot]=rt;
        }
        //fa[trie[rt][x]]=rt;
        rt=trie[rt][x];
    }
    void build(){
        queue<int>q;
        for(int i = 0; i < 26; i++){
            if(trie[0][i]){
                //fail[trie[0][i]]=0;
                //v[0].pb(trie[0][i]);
                q.push(trie[0][i]);
            }
        }
        while(!q.empty()){
            int now = q.front();
            q.pop();
            for(int i = 0; i < 26; i++){
                ////让这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个相同节点)
                if(trie[now][i]){
                    fail[trie[now][i]]=trie[fail[now]][i];
                    //v[trie[fail[now]][i]].pb(trie[now][i]);
                    q.push(trie[now][i]);
                }
                else trie[now][i]=trie[fail[now]][i];
                //否则就让当前节点的这个子节点指向当前节点fail指针的这个子节点   
            }
            v[fail[now]].pb(now);
        }
    }
    
}ac;
char a[maxn];
int bg[maxn],ed[maxn];
int S[maxn],tot;
void gao(int x){
    S[++tot]=x;
    bg[x]=tot;
    for(int i = 0; i < (int)v[x].size(); i++){
        int y =v[x][i];
        gao(y);
    }
    //S[++tot]=x;
    ed[x]=tot;
}
int tree[maxn];
int lowbit(int x){return x&-x;}
void add(int x, int c){
    for(int i = x; i <= tot; i+=lowbit(i)){tree[i]+=c;}
}
int sum(int x){
    int ans =0;
    for(int i = x; i; i-=lowbit(i))ans+=tree[i];
    return ans;
}
vector<PI>Q[maxn];
int ans[maxn];
/*
void dfs(int x){
    //printf("%d\n",x);
    add(bg[x],1);
    for(int i = 0; i < (int)Q[x].size(); i++){
        int y = Q[x][i].fst;
        ans[Q[x][i].sc]=sum(ed[y])-sum(bg[y]-1);
    }
    for(int i = 0; i < 26; i++){
        int y = ac.trie[x][i];
        if(!y||(y==ac.trie[ac.fail[x]][i]))continue;
        dfs(y);
    }
    add(bg[x],-1);
}*/
void sv(){
    int now = 0;
    int n = strlen(a+1);
    int world=0;
    for(int i = 1; i <= n; i++){
        if(a[i]=='B'){
            add(bg[now],-1);
            now=ac.fa[now];
            continue;
        }
        else if(a[i]=='P'){
            world++;
            for(int j = 0; j < (int)Q[now].size(); j++){
                int x = Q[now][j].fst;
                int y = Q[now][j]. sc;
                ans[y]=sum(ed[x])-sum(bg[x]-1);
            }
            continue;
        }
        else{
            int x=a[i]-'a';
            now=ac.trie[now][x];
            add(bg[now],1);
        }
    }
}
int main(){
    ac.init();
    tot=0;
    scanf("%s", a+1);
    int n = strlen(a+1);
    for(int i = 1; i <= n; i++){
        ac.add(a[i]);
    }
    ac.build();
    int m;
    scanf("%d", &m);
    for(int i = 1; i <= m; i++){
        int x,y;
        scanf("%d %d", &x, &y);
        x=id[x];y=id[y];
        Q[y].pb(make_pair(x,i));
    }
    gao(0);
    //dfs(0);
    sv();
    for(int i = 1; i <= m; i++){
        printf("%d\n",ans[i]);
    }
    return 0;
}
/*
aPaPBbP
3
1 2
1 3
2 3

a
aa
aa
 */

バージョン2

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
     
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
 
using namespace std;
 
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;
 
const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 3e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);
 
vector<int>v[maxn];
int id[maxn];
int h[maxn];
struct AC{
    //局部变量没有默认0!
    int trie[maxn][26];
    int num[maxn];//单词出现次数
    int fail[maxn],fa[maxn];
    int vis[maxn];//ask函数用到
    int tot,rt;
    int ntot;
    int H;
    //多测可写个init
    void init(){tot=0;mem(vis,0);mem(trie,0);rt=0;ntot=0;H=0;}
    void add(char c){
        if(c=='P'){
            num[rt]++;
            id[++ntot]=rt;
            return;
        }
        if(c=='B'){
            rt=fa[rt];H--;
            return;
        }
        int x = c-'a';
        if(!trie[rt][x]){
            trie[rt][x]=++tot;
            fa[tot]=rt;
        }
        //fa[trie[rt][x]]=rt;
        rt=trie[rt][x];
        h[rt]=++H;
    }
    void build(){
        queue<int>q;
        for(int i = 0; i < 26; i++){
            if(trie[0][i]){
                fail[trie[0][i]]=0;
                //v[0].pb(trie[0][i]);
                q.push(trie[0][i]);
            }
        }
        while(!q.empty()){
            int now = q.front();
            q.pop();
            for(int i = 0; i < 26; i++){
                ////让这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个相同节点)
                if(trie[now][i]){
                    fail[trie[now][i]]=trie[fail[now]][i];
                    //v[trie[fail[now]][i]].pb(trie[now][i]);
                    q.push(trie[now][i]);
                }
                else trie[now][i]=trie[fail[now]][i];
                //否则就让当前节点的这个子节点指向当前节点fail指针的这个子节点   
            }
            v[fail[now]].pb(now);
        }
    }
     
}ac;
char a[maxn];
int bg[maxn],ed[maxn];
int S[maxn],tot;
void gao(int x){
    S[++tot]=x;
    bg[x]=tot;
    for(int i = 0; i < (int)v[x].size(); i++){
        int y =v[x][i];
        gao(y);
    }
    //S[++tot]=x;
    ed[x]=tot;
}
int tree[maxn];
int lowbit(int x){return x&-x;}
void add(int x, int c){
    for(int i = x; i <= tot; i+=lowbit(i)){tree[i]+=c;}
}
int sum(int x){
    int ans =0;
    for(int i = x; i; i-=lowbit(i))ans+=tree[i];
    return ans;
}
vector<PI>Q[maxn];
int ans[maxn];
 
void dfs(int x){
    //printf("==%d\n",x);
    add(bg[x],1);
    for(int i = 0; i < (int)Q[x].size(); i++){
        int y = Q[x][i].fst;
        ans[Q[x][i].sc]=sum(ed[y])-sum(bg[y]-1);
    }
    for(int i = 0; i < 26; i++){
        int y = ac.trie[x][i];
        if(!y||h[y]<=h[x])continue;
        dfs(y);
    }
    add(bg[x],-1);
}
void sv(){
    int now = 0;
    int n = strlen(a+1);
    int world=0;
    for(int i = 1; i <= n; i++){
        if(a[i]=='B'){
            add(bg[now],-1);
            now=ac.fa[now];
            continue;
        }
        else if(a[i]=='P'){
            world++;
            for(int j = 0; j < (int)Q[now].size(); j++){
                int x = Q[now][j].fst;
                int y = Q[now][j]. sc;
                ans[y]=sum(ed[x])-sum(bg[x]-1);
            }
            continue;
        }
        else{
            int x=a[i]-'a';
            now=ac.trie[now][x];
            add(bg[now],1);
        }
    }
}
int main(){
    ac.init();
    tot=0;
    scanf("%s", a+1);
    int n = strlen(a+1);
    for(int i = 1; i <= n; i++){
        ac.add(a[i]);
    }
    ac.build();
    int m;
    scanf("%d", &m);
    for(int i = 1; i <= m; i++){
        int x,y;
        scanf("%d %d", &x, &y);
        x=id[x];y=id[y];
        Q[y].pb(make_pair(x,i));
    }
    gao(0);
    dfs(0);
    //sv();
    for(int i = 1; i <= m; i++){
        printf("%d\n",ans[i]);
    }
    return 0;
}
/*
asPdPasPddPhBdPhPnaPasP
8
1 5 
2 6 
3 8 
4 3
7 7 
2 5 
6 8
1 8
 
a
aa
aa
 */

おすすめ

転載: www.cnblogs.com/wrjlinkkkkkk/p/11597485.html
おすすめ