zoukankan      html  css  js  c++  java
  • [NOI2011] 阿狸的打字机

    对一台打字机,有两个功能字符:P 表示打印当前缓存中的串,B 表示删去缓存末尾的一个字符。给定一个操作串。你需要回答 (m) 个询问,每个询问指定 ((x,y)),求第 (x) 个打印的字符串在第 (y) 个打印的字符串中出现了多少次。

    Solution

    (S) 是否在 (T) 出现,就是问 ACAM 上,(T) 到 Trie 根的沿着 Trans 边路径上,有没有 (S) 在 fail 树上的子树内的结点

    先处理操作串来建 Trie,遇到 P 操作就将当前结点打标记,遇到 B 操作就退回到 Trie 上的父亲结点

    对于询问 ((x,y)),就是要求 fail 树上以 (x) 为根的子树内,有多少个 (y) 沿着 Trie 树上的边走到根的路径上的结点

    注意这里的 Trie 树和 fail 树上的边要加以区分,这就是为什么不能直接套个链剖走人

    考虑离线,将 Trie 树 DFS 一遍,同时维护一个桶,桶中下标为 (i) 的位置表示当前所在点到根的链上是否有 (i) 这个点

    这个维护方式是显然的,每次 DFS 进入一个点时就 (+1),完成一个点时就 (-1)

    我们将每个询问挂在 (y) 上,那么进入 (y) 后,询问 (x) 这个点的子树和即可

    于是桶需要按照 DFS 序做下标,需要用树状数组维护

    (注意区分这里所涉及的 Trans 图边,Fail 树边,Trie 树边)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1000005;
    const int dbg = 0;
    
    int ar[N]; // index: 1 ~ N
    int lowbit(int t) { return t & (-t); }
    void add(int i, int v) {
        if(i==0) return;
    	for (; i < N; ar[i] += v, i += lowbit(i));
    }
    int sum(int i) {
    	int s = 0;
    	for (; i > 0; s += ar[i], i -= lowbit(i));
    	return s;
    }
    int sum(int i,int j) {
        return sum(j) - sum(i-1);
    }
    
    queue <int> q;
    int c[N][26],fi[N],cnt,tot,fa[N],pos[N];
    vector <int> val[N];
    vector <int> g[N];
    vector <int> tr[N];
    void ins(char *str) {
        int len=strlen(str), p=0;
        for(int i=0; i<len; i++) {
            if(str[i]=='B') {p=fa[p]; continue;}
            if(str[i]=='P') {val[p].push_back(++tot); pos[tot]=p; continue;}
            int v=str[i]-'a';
            if(!c[p][v]) c[p][v]=++cnt,tr[p].push_back(c[p][v]);
            fa[c[p][v]]=p;
            p=c[p][v];
        }
    }
    void build() {
        for(int i=0; i<26; i++) if(c[0][i]) fi[c[0][i]]=0, q.push(c[0][i]);
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            for(int i=0; i<26; i++)
                if(c[u][i]) fi[c[u][i]]=c[fi[u]][i], q.push(c[u][i]);
                else c[u][i]=c[fi[u]][i];
        }
    }
    void query(char *s) {
        int len=strlen(s);
        int p=0;
        for(int i=0; i<len; i++) {
            p=c[p][s[i]-'a'];
        }
    }
    
    char str[N];
    int dfn[N],fin[N],ind,ans[N];
    
    struct cquery {
        int x,y,id;
    };
    vector <cquery> qu[N];
    
    void dfs(int p) {
        dfn[p]=++ind;
        for(int q:g[p]) dfs(q);
        fin[p]=ind;
    }
    
    void solve(int p) {
        add(dfn[p],1);
        for(cquery t:qu[p]) {
            ans[t.id]=sum(dfn[t.x],fin[t.x]);
        }
        for(int q:tr[p]) solve(q);
        add(dfn[p],-1);
    }
    
    signed main() {
        ios::sync_with_stdio(false);
        cin>>str;
        ins(str);
        build();
        for(int i=1;i<=cnt;i++) g[fi[i]].push_back(i);
        dfs(0);
        if(dbg) {
            cout<<"fail"<<endl;
            for(int i=0;i<=cnt;i++) {
                for(int j:g[i]) cout<<i<<"->"<<j<<endl;
            }
            cout<<"trans"<<endl;
            for(int i=0;i<=cnt;i++) {
                for(int j:tr[i]) cout<<i<<"->"<<j<<endl;
            }
            for(int i=0;i<=cnt;i++) cout<<dfn[i]<<" ";
            cout<<endl;
        }
        int m,x,y;
        cin>>m;
        for(int i=1;i<=m;i++) {
            cin>>x>>y;
            x=pos[x];
            y=pos[y];
            if(dbg) cout<<"translated "<<x<<" "<<y<<endl;
            qu[y].push_back({x,y,i});
        }
        solve(0);
        for(int i=1;i<=m;i++) {
            cout<<ans[i]<<endl;
        }
    }
    
    
  • 相关阅读:
    Javascript设计模式理论与实战:单例模式
    详解CSS盒模型
    linux添加计划任务
    python删除目录下七天前创建的文件
    centos上源码安装clang 3.8
    使用postman发送数据并构建collections执行测试
    python多线程实现同时执行两个while循环
    使用Python写Windows Service服务程序
    用Pyinstaller打包发布exe应用
    使用Jmeter监测服务器cpu、内存等性能
  • 原文地址:https://www.cnblogs.com/mollnn/p/12448558.html
Copyright © 2011-2022 走看看