zoukankan      html  css  js  c++  java
  • [COCI2015] Divljak

    (n) 个询问串 (S_i),有一个初始为空的字符串集合 (T),接下来有 (q) 个操作,每次向集合中添加一个字符串,或给定 (x) 询问集合中有多少个字符串包含 (S_x)

    Solution

    考虑对 (S_i) 建立 ACAM,建出 (fail) 树,一个点发生匹配,则需要修改它到根的链,询问就是查询一个点的值

    这样需要树链剖分,我们可以差分一下,那么每次修改的就是一个点,询问的是一个子树的和

    于是我们求出 (fail) 树的 DFS 序,用树状数组维护,每次修改时,把输入的串扔到 ACAM 上跑,匹配上的结点都 (+1),这里需要开个标记数组,防止同一个输入串对同一个结点多次 (+1)

    每次询问时,就输出 (S_x) 对应的子树的子树和即可

    很显然上面这个解法是错误的!

    虽然我们保证了对于每个询问串,我们只对相同的结点打一次标记,但是前缀和回去的的结果仍然会重复

    所以我们需要另一个方法来解决这个路径并的问题

    上述解法的基础上,考虑将所有打过标记的点拿出来,按照 (dfs) 序排序,对相邻节点的 (lca) 位置 (-1) 即可

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 2000005;
    
    int ar[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 p,int q) {
        return sum(q)-sum(p-1);
    }
    
    int dfn[N],idfn[N],fin[N],dep[N],fa[N][21];
    
    int lca(int p,int q) {
        if(dep[p]<dep[q]) swap(p,q);
        for(int i=20;i>=0;--i) if(dep[fa[p][i]]>=dep[q]) p=fa[p][i];
        for(int i=20;i>=0;--i) if(fa[p][i]-fa[q][i]) p=fa[p][i],q=fa[q][i];
        if(p==q) return p;
        else return fa[p][0];
    }
    
    struct ACA {
        queue <int> q;
        int c[N][26],val[N],fi[N],cnt,ans[1005];
        void init() {
            memset(c,0,sizeof c);
            memset(val,0,sizeof val);
            memset(fi,0,sizeof fi);
            memset(ans,0,sizeof ans);
            cnt=0;
        }
        int ins(char *str,int id) {
            int len=strlen(str), p=0;
            for(int i=0; i<len; i++) {
                int v=str[i]-'a';
                if(!c[p][v]) c[p][v]=++cnt;
                p=c[p][v];
            }
            val[p]=id;
            return p;
        }
        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) {
            set<int> st;
            int len=strlen(s);
            int p=0;
            for(int i=0; i<len; i++) {
                p=c[p][s[i]-'a'];
                if(p&&st.find(dfn[p])==st.end()) {
                    st.insert(dfn[p]);
                    add(dfn[p],1);
                }
            }
            vector <int> vec;
            for(auto i=st.begin();i!=st.end();i++) vec.push_back(*i);
            for(int i=1;i<vec.size();i++) {
                add(dfn[lca(idfn[vec[i]],idfn[vec[i-1]])],-1);
            }
        }
    } acam;
    
    vector<int> g[N];
    int n,q,endid[N],ind;
    char str[N];
    
    void dfs(int p) {
        dfn[p]=++ind; idfn[ind]=p;
        for(int q:g[p]) fa[q][0]=p, dep[q]=dep[p]+1, dfs(q);
        fin[p]=ind;
    }
    
    signed main() {
        ios::sync_with_stdio(false);
        cin>>n;
        for(int i=1; i<=n; i++) {
            cin>>str;
            endid[i]=acam.ins(str,i);
        }
        acam.build();
        for(int i=1; i<=acam.cnt; i++) g[acam.fi[i]].push_back(i);
        dfs(0);
        for(int j=1;j<=20;j++) {
            for(int i=1;i<=acam.cnt;i++) {
                fa[i][j]=fa[fa[i][j-1]][j-1];
            }
        }
        cin>>q;
        for(int i=1; i<=q; i++) {
            int t1,t2;
            cin>>t1;
            if(t1==1) {
                cin>>str;
                acam.query(str);
            } else {
                cin>>t2;
                cout<<sum(dfn[endid[t2]],fin[endid[t2]])<<endl;
            }
        }
    }
    
    
    
  • 相关阅读:
    【草稿】自定义ASP.NET MVC Html辅助方法
    Python安装(64位Win8.1专业版)
    部署WP程序到自己的手机
    C++中vector小学习,顺便查了下<stdio.h>(或<cstdio>)
    关于ENVI5.0菜单栏不能正常显示(win7 x86系统)
    如何让一个精灵跟随触点移动
    GDAL在VS下配置测试
    【docker】修改现有容器的端口
    Django channles线上部署(腾讯云)
    【leafletjs】添加标记、轨迹线与删除标记、轨迹线
  • 原文地址:https://www.cnblogs.com/mollnn/p/12443298.html
Copyright © 2011-2022 走看看