• 2434: [Noi2011]阿狸的打字机


    ac自动机,bit,dfs序。

    本文所有的stl都是因为自己懒得实现。

    首先x在y里面出现,就意味y节点可以顺着fail回去。

    反向建出一个fail数,然后搞出dfs序列。找出x对应的区间有多少个y。

    再用离线操作,把每个y需要计算的x事先保存下来。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<vector>
    using namespace std;
    const int maxn = 100000 + 10;
    
    char s[maxn];
    int a[maxn][26];
    int g[maxn],v[maxn],next[maxn],eid;
    int pos[maxn],cnt;
    int fa[maxn],fail[maxn],L[maxn],R[maxn],query[maxn][3];
    int m,n,u,dfn,vid;
    vector<int> Q[maxn];
    queue<int> q;
    
    struct BIT {
        int a[maxn<<1],n;
        
        int lowbit(int x) {
            return (x & -x);
        }
        
        void add(int x,int d) {
            //printf("c %d %d
    ",x,d);
            for(;x<=n;x+=lowbit(x)) a[x]+=d;
            //printf("c");
        }
        
        int query(int x) {
            int res=0;
            for(;x;x-=lowbit(x)) res+=a[x];
            return res;    
        }
        
        void init(int _n) {
            n=_n;
        }
    }bit;
    
    void addedge(int a,int b) {
        v[eid]=b; next[eid]=g[a]; g[a]=eid++;
    }
    
    void dfs(int u) {
        L[u]=++dfn;
        for(int i=g[u];~i;i=next[i]) dfs(v[i]);
        R[u]=dfn;
    }
    
    void get_trie() {
        for(int i=0;i<26;i++) a[0][i]=1;
        
        int p=1,c;vid=1;
        for(int i=0;i<n;i++) {
            //printf("f[%d] = %d
    ",i,p);
            if(s[i]=='P') pos[++cnt]=p;
            else if(s[i]=='B') p=fa[p];
            else {
                c=s[i]-'a';
                if(!a[p][c]) 
                    a[p][c]=++vid,fa[vid]=p;
                p=a[p][c];
            }
            //printf("f[%d] = %d
    ",i,p);
        }
    }
    
    void debug(int p) {
    }
    
    void get_fail() {
        fail[1]=0;
        q.push(1);
        
        while(!q.empty()) {
            u=q.front();q.pop();
            for(int k=0,p;k<26;k++)
            if(a[u][k]) {
                for(p=fail[u];p&&!a[p][k];p=fail[p]);
                fail[a[u][k]]=a[p][k];
                q.push(a[u][k]);
            }
        }
    }
    
    void get_tree() {
        for(int i=1;i<=vid;i++) addedge(fail[i],i);
        dfs(1);
    }
    
    void build() {
        memset(g,-1,sizeof(g));
        scanf("%s",s);n=strlen(s);
        
        get_trie();
        //debug(1);
        get_fail();
        get_tree(); 
        
        scanf("%d",&m);
        for(int i=1;i<=m;i++) {
            scanf("%d %d",&query[i][0],&query[i][1]);
            query[i][0]=pos[query[i][0]];
            query[i][1]=pos[query[i][1]];
            Q[query[i][1]].push_back(i);
        }
        
    }
    
    void solve() {
        bit.init(n<<1);
        int p=1;
        for(int i=0;i<n;i++) {
            //printf("s[i]=%c
    ",s[i]);
            if(s[i]=='P') for(int j=0;j<Q[p].size();j++) 
                query[Q[p][j]][2]=bit.query(R[query[Q[p][j]][0]])-bit.query(L[query[Q[p][j]][0]]-1);
            else if(s[i]=='B') bit.add(L[p],-1),p=fa[p];
            else p=a[p][s[i]-'a'],bit.add(L[p],1);
            //printf(" %d
    ",i);
        }
        
        for(int i=1;i<=m;i++) printf("%d
    ",query[i][2]);
    }
    
    int main() {
        build();
        solve();
        
        return 0;
    }
  • 相关阅读:
    再谈树形dp
    洛谷 P3627 [APIO2009]抢掠计划
    树状数组
    树形dp 入门
    洛谷P2014 选课
    洛谷P2015 二叉苹果树
    9 vue.js 被观察数组的变异方法
    8 vue的v-model指令学习
    7vue-事件修饰符
    6.vue事件绑定-click
  • 原文地址:https://www.cnblogs.com/invoid/p/5444835.html
Copyright © 2020-2023  润新知