zoukankan      html  css  js  c++  java
  • HDU 4117 GRE Words

    这道题不难想到这样的dp。

    dp[字符串si] = 以si为结尾的最大总权值。

    dp[si] = max(dp[sj]) ,1.j < i,2.sj是si的子串。

    对于第二个条件,是一个多模版串匹配的问题,可以用AC自动机。

    预先O(m)把AC自动机建好,然后动态更新AC自动机上的dp值,

    匹配的时候,指向字符的指针移动总共是O(m),

    而每个单词,fail指针走寻找后缀却是O(m),即使改成后缀链接也是O(n)。too slow!

    找到一个单词后,需要避免找后缀,动态维护这个单词的dp值。

    一开始所有单词的dp都是0。

    更新的时候,dp[si]需要更新所有dp[sj],其中si是sj的后缀。

    如果父节点是子节点的后缀,把所有的单词(包括空后缀)连接起来将会得到以空字符串为根的后缀链接树。

    这样就变成一个更新子树的问题,dfs把树形转成线性以后可以用线段树来维护。

    询问单点最大值,区间更新O(logn)。

    复杂度O(mlogn)

    潜在的坑点:

    1.Trie个结点可能对应多个单词,如果只更新了其中一个单词的线性区间RE...(map,前向链表,vector都可以搞

    /*********************************************************
    *            ------------------                          *
    *   author AbyssFish                                     *
    **********************************************************/
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    
    
    const int LEN = 3e5+5;
    const int MAXN = 2e4+5;
    
    int W[MAXN], S[MAXN];
    int N;
    char s[LEN];
    
    int hd[LEN];
    int nx[MAXN], to[MAXN], ec;
    
    void add_e(int u,int v)
    {
        to[ec] = v;
        nx[ec] = hd[u];
        hd[u] = ec++;
    }
    #define eachedge int i = hd[u]; ~i; i = nx[i]
    inline void init_g(int n){ memset(hd,-1,n<<2); ec = 0; }
    int L[MAXN], R[MAXN], dfs_clk; //string's linear suffix link tree id
    const int ST_SIZE = 1<<16;
    int dp[ST_SIZE];
    
    #define para int o = 1,int l = 0,int r = dfs_clk
    #define lo (o<<1)
    #define ro (o<<1|1)
    #define Tvar int md = (l+r)>>1;
    #define lsn lo,l,md
    #define rsn ro,md,r
    #define insd ql<=l&&r<=qr
    
    void build(para)
    {
        dp[o] = 0;
        if(r-l>1){
            Tvar
            build(lsn);
            build(rsn);
        }
    }
    
    void update(int ql,int qr,int v,para)
    {
        if(insd){
            dp[o] = max(dp[o],v);
        }
        else {
            Tvar
            if(ql < md) update(ql,qr,v,lsn);
            if(qr > md) update(ql,qr,v,rsn);
        }
    }
    
    int query(int p,para)
    {
        int re = 0;
        while(r-l>1){
            Tvar
            if(p<md){
                o = lo; r = md;
            }
            else {
                o = ro; l = md;
            }
            re = max(re,dp[o]);
        }
        return re;
    }
    
    
    
    
    const int sigma_size = 26, MAXND = LEN;
    struct AhoCorasick_automata
    {
        #define idx(x) (x-'a')
        int ch[MAXND][sigma_size];
    
        int f[MAXND];
        int last[MAXND];
        int cnt;
    
        int val[MAXND];
        int nx_val[MAXN];
        void add_v(int o,int x)
        {
            nx_val[x] = val[o];
            val[o] = x;
        }
    
        int newNode()
        {
            int i = ++cnt;
            memset(ch[i],0,sizeof(ch[i]));
            val[i] = 0;
            return i;
        }
    
    
        void init()
        {
            cnt = -1; newNode();
        }
    
        int add(char *s,int id)
        {
            int u = 0, i, c;
            for(i = 0; s[i]; i++){
                c = idx(s[i]);
                if(!ch[u][c]){
                    ch[u][c] = newNode();
                }
                u = ch[u][c];
            }
            add_v(u,id);
            return i;
        }
    
        queue<int> q;
        void getFail()
        {
            int u, c, v, r;
            //f[0] = 0; last[0] = 0;
            for(c = 0; c < sigma_size; c++){
                u = ch[0][c];
                if(u){
                    q.push(u);
                    f[u] = 0;
                    last[u] = 0;
                }
            }
            while(!q.empty()){
                r = q.front(); q.pop();
                for(c = 0; c < sigma_size; c++){
                    u = ch[r][c];
                    if(u){
                        q.push(u);
                        v = f[u] = ch[f[r]][c];
                        last[u] = val[v] ? v : last[v];
                    }
                    else ch[r][c] = ch[f[r]][c];
                }
            }
        }
    
        void dfs(int u)
        {
            int le = dfs_clk++;
            for(eachedge){
                dfs(to[i]);
            }
            int ri = dfs_clk;
            for(int id = val[u]; id; id = nx_val[id]){
                L[id] = le; R[id] = ri;
            }
        }
    
        void buildTree()
        {
            init_g(cnt+1);
            for(int u = 1; u <= cnt; u++)if(val[u]){
                add_e(last[u],u);
            }
            dfs_clk = 0;
            dfs(0);
        }
    
        void work()
        {
            int i,j,c,u,id;
            int ans = 0, mx;
            build();
            for(i = 1; i <= N; i++){
                u = 0; mx = 0;
                for(j = S[i-1]; j < S[i]; j++){
                    c = idx(s[j]);
                    u = ch[u][c];
                    if(val[u]){
                        id = val[u];
                        mx = max(mx, query(L[id]));
                    }
                    else if(last[u]){
                        id = val[last[u]];
                        mx = max(mx, query(L[id]));
                    }
                }
                if(W[i] > 0){
                    ans = max(ans, mx += W[i]);
                    update(L[i],R[i],mx);
                }
            }
            printf("%d
    ",ans);
        }
    
    }ac;
    
    
    void solve()
    {
        scanf("%d",&N);
        ac.init();
        for(int i = 1; i <= N; i++){
            scanf("%s%d",s+S[i-1],W+i);
            S[i] = ac.add(s+S[i-1],i)+S[i-1];
        }
        ac.getFail();
        ac.buildTree();
        ac.work();
    }
    
    //#define LOCAL
    int main()
    {
    #ifdef LOCAL
        freopen("data.txt","r",stdin);
    #endif
        int T, kas = 0; scanf("%d",&T);
        while(++kas <= T){
            printf("Case #%d: ",kas);
            solve();
        }
        return 0;
    }
  • 相关阅读:
    扩展中国剩余定理
    bzoj 3816&&uoj #41. [清华集训2014]矩阵变换
    THUSC2017
    bzoj 4521: [Cqoi2016]手机号码
    bzoj 4871: [Shoi2017]摧毁“树状图”
    bzoj 2300 : [HAOI2011]防线修建
    bzoj 3853 : GCD Array
    HEOI 2017 游记
    bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机模板
    bzoj 4310 跳蚤
  • 原文地址:https://www.cnblogs.com/jerryRey/p/5051900.html
Copyright © 2011-2022 走看看