SPOJ8093 Sevenk Love Oimaster 广义SAM、树状数组

传送门


对于所有模板串建立广义\(SAM\),插入第\(i\)个串的过程中给经过的点打上第\(i\)种标记;然后将每一个询问串放在\(SAM\)上跑一边得到该串对应在\(SAM\)的状态,如果为空答案就是\(0\),否则我们需要求这个状态的标记数量。

因为如果某个串被打了某些标记,那么它在\(parent\)树上的祖先也要有这些标记。所以问题等价于:某个点在\(parent\)树上的子树中有多少种标记,放到\(parent\)树的\(dfs\)序上就是HH的项链。将询问离线,跑出dfs序然后树状数组解决。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
//This code is written by Itst
using namespace std;

int N , M;
const int MAXN = 2e5 + 7;

namespace SAM{
    int Lst[MAXN] , Sst[MAXN] , fa[MAXN] , trans[MAXN][26];
    int cnt = 1 , L;
    char s[MAXN];
    vector < int > col[MAXN];
    
    int insert(int p , int len , int x){
        int t = ++cnt;
        Lst[t] = len;
        while(p && !trans[p][x]){
            trans[p][x] = t;
            p = fa[p];
        }
        if(!p){
            Sst[t] = fa[t] = 1;
            return t;
        }
        int q = trans[p][x];
        Sst[t] = Lst[p] + 2;
        if(Lst[q] == Lst[p] + 1){
            fa[t] = q;
            return t;
        }
        int k = ++cnt;
        memcpy(trans[k] , trans[q] , sizeof(trans[k]));
        Lst[k] = Lst[p] + 1;
        Sst[k] = Sst[q];
        Sst[q] = Lst[p] + 2;
        fa[k] = fa[q];
        fa[q] = fa[t] = k;
        while(trans[p][x] == q){
            trans[p][x] = k;
            p = fa[p];
        }
        return t;
    }

    vector < int > ch[MAXN];
    int dfn[MAXN] , sz[MAXN] , ind[MAXN] , ts;

    void dfs(int x){
        dfn[x] = ++ts;
        ind[ts] = x;
        sz[x] = 1;
        for(int i = 0 ; i < ch[x].size() ; ++i){
            dfs(ch[x][i]);
            sz[x] += sz[ch[x][i]];
        }
    }
    
    void init(){
        for(int i = 2 ; i <= cnt ; ++i)
            ch[fa[i]].push_back(i);
        dfs(1);
    }

#define PII pair < int , int >
#define st first
#define nd second
#define PIII pair < PII , int >
#define lowbit(i) ((i) & -(i))
    int ans[MAXN] , BIT[MAXN] , bef[MAXN];
    vector < PIII > query;
    
    PII go(){
        scanf("%s" , s + 1);
        int L = strlen(s + 1) , cur = 1;
        for(int i = 1 ; i <= L ; ++i)
            if(trans[cur][s[i] - 'a'])
                cur = trans[cur][s[i] - 'a'];
            else
                return PII(0 , 0);
        return PII(sz[cur] + dfn[cur] - 1 , dfn[cur]);
    }

    void modify(int x , int num){
        if(!x) return;
        while(x <= cnt){
            BIT[x] += num;
            x += lowbit(x);
        }
    }

    int get(int x){
        int sum = 0;
        while(x){
            sum += BIT[x];
            x -= lowbit(x);
        }
        return sum;
    }
    
    void work(){
        for(int i = 1 ; i <= M ; ++i){
            PII t = go();
            if(t.st)
                query.push_back(PIII(t , i));
        }
        sort(query.begin() , query.end());
        int cur = 0;
        for(int i = 0 ; i < query.size() ; ++i){
            while(cur < query[i].st.st){
                ++cur;
                for(int j = 0 ; j < col[ind[cur]].size() ; ++j){
                    modify(bef[col[ind[cur]][j]] , -1);
                    modify(bef[col[ind[cur]][j]] = cur , 1);
                }
            }
            ans[query[i].nd] = get(query[i].st.st) - get(query[i].st.nd - 1);
        }
        for(int i = 1 ; i <= M ; ++i)
            cout << ans[i] << endl;
    }
}

namespace Trie{
    int ch[MAXN][26] , dep[MAXN] , ind[MAXN] , cnt = 1;
    char s[MAXN];
    vector < int > col[MAXN];
    
    void insert(int c){
        scanf("%s" , s + 1);
        int L = strlen(s + 1) , cur = 1;
        for(int i = 1 ; i <= L ; ++i){
            if(!ch[cur][s[i] - 'a']){
                ch[cur][s[i] - 'a'] = ++cnt;
                dep[cnt] = dep[cur] + 1;
            }
            cur = ch[cur][s[i] - 'a'];
            col[cur].push_back(c);
        }
    }

    void build(){
        queue < int > q;
        q.push(ind[1] = 1);
        while(!q.empty()){
            int t = q.front();
            q.pop();
            for(int i = 0 ; i < 26 ; ++i)
                if(ch[t][i]){
                    ind[ch[t][i]] = SAM::insert(ind[t] , dep[ch[t][i]] , i);
                    SAM::col[ind[ch[t][i]]] = col[ch[t][i]];
                    q.push(ch[t][i]);
                }
        }
        SAM::init();
    }
}

int main(){
    #ifndef ONLINE_JUDGE
    freopen("in" , "r" , stdin);
    //freopen("out" , "w" , stdout);
    #endif
    cin >> N >> M;
    for(int i = 1 ; i <= N ; ++i)
        Trie::insert(i);
    Trie::build();
    SAM::work();        
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Itst/p/10436129.html