zoukankan      html  css  js  c++  java
  • [Codeforces 666E] Forensic Examination

    [题目链接]

             https://codeforces.com/problemset/problem/666/E

    [算法]

             首先建立广义后缀自动机

             对于自动机上的每一个节点建一棵动态开点线段树

             对于每次询问 ,

             S[pl..pr]所表示节点可以在多串后缀树上倍增得到

             那么我们需要的就是计算该节点中出现次数最多的串

             线段树合并即可

             时间复杂度 : O(NlogN)

    [代码]

             

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int MAXP = 1e5 + 10;
    const int MAXN = 5e5 + 10;
    const int ALPHA = 26;
    const int MAXLOG = 20;
    
    int n , m , q;
    int anc[MAXP][MAXLOG] , rt[MAXP] , pos[MAXN] , len[MAXN];
    char S[MAXP] , s[MAXN];
    
    struct Segment_Tree
    {
        int sz;
        int lc[MAXP * 60] , rc[MAXP * 60] , val[MAXP * 60] , loc[MAXP * 60];
        Segment_Tree()
        {
            sz = 0;    
        } 
        inline void update(int x)
        {
            if (val[lc[x]] >= val[rc[x]])
            {
                val[x] = val[lc[x]];
                loc[x] = loc[lc[x]];
            } else
            {
                val[x] = val[rc[x]];
                loc[x] = loc[rc[x]];
            }
        }
        inline void modify(int &now , int l , int r , int x , int value)
        {
            if (!now) now = ++sz;
            if (l == r)
            {
                val[now] += value;
                loc[now] = l;
            } else
            {
                int mid = (l + r) >> 1;
                if (mid >= x) modify(lc[now] , l , mid , x , value);
                else modify(rc[now] , mid + 1 , r , x , value);
                update(now);
            }
        }
        inline int merge(int x , int y , int l , int r)
        {
            if (!x || !y)
                return x + y;
            int p = ++sz;
            if (l == r)
            {
                val[p] = val[x] + val[y];
                loc[p] = l;
                return p;
            }
            int mid = (l + r) >> 1;
            lc[p] = merge(lc[x] , lc[y] , l , mid);
            rc[p] = merge(rc[x] , rc[y] , mid + 1 , r);
            update(p);
            return p;
        }
        inline pair<int , int> query(int now , int l , int r , int ql , int qr)
        {
            if (!now) 
                return make_pair(0 , 0); 
            if (l == ql && r == qr)
                return make_pair(loc[now] , val[now]);
            int mid = (l + r) >> 1;
            if (mid >= qr) return query(lc[now] , l , mid , ql , qr);
            else if (mid + 1 <= ql) return query(rc[now] , mid + 1 , r , ql , qr);
            else
            {
                pair<int , int> t1 = query(lc[now] , l , mid , ql , mid);
                pair<int , int> t2 = query(rc[now] , mid + 1 , r , mid + 1 , qr);
                if (t1.second >= t2.second) return t1;
                else return t2; 
            }
        }
    } SGT;
    struct Suffix_Automaton
    {
        int sz , last;
        int father[MAXP] , child[MAXP][ALPHA] , depth[MAXP];
        vector< int > a[MAXP];
        multiset< int > s[MAXP];    
        Suffix_Automaton()
        {
            sz = 1;    
            last = 1;
        }    
        inline int new_node(int dep)
        {
            depth[++sz] = dep;
            memset(child[sz] , 0 , sizeof(child[sz]));
            father[sz] =  0;
            a[sz].clear();
            s[sz].clear();
            return sz;
        }
        inline void extend(int ch , int c)
        {
                  int np = child[last][ch];
                  if (np)
                  {
                if (depth[np] == depth[last] + 1) 
                {
                    s[np].insert(c);
                    last = np;
                } else
                {
                  int nq = new_node(depth[last] + 1);
                  father[nq] = father[np];
                  father[np] = nq;
                  memcpy(child[nq] , child[np] , sizeof(child[np]));
                  for (int p = last; child[p][ch] == np; p = father[p]) 
                          child[p][ch] = nq;
                  s[nq].insert(c);
                  last = nq;
                  }
                  } else
                  {
                  int np = new_node(depth[last] + 1);
                  int p = last;
                  while (child[p][ch] == 0)
                  {
                    child[p][ch] = np;
                    p = father[p];
                  }
                  if (child[p][ch] == np)
                  {
                    father[np] = 1;
                    s[np].insert(c);
                    last = np;
                    return;
                  }
                  int q = child[p][ch];
                  if (depth[q] == depth[p] + 1)
                  {
                    father[np] = q;
                    s[np].insert(c);
                    last = np;
                    return; 
                  } else
                  {
                    int nq = new_node(depth[p] + 1);
                    father[nq] = father[q];
                    father[np] = father[q] = nq;
                    memcpy(child[nq] , child[q] , sizeof(child[q]));
                    while (child[p][ch] == q)
                    {
                        child[p][ch] = nq;
                        p = father[p];
                    }
                    s[np].insert(c);
                    last = np;
                    return;
                  }
                   }
        }
        inline void insert(char *s , int col)
        {
            last = 1;
            for (int i = 1; i <= strlen(s + 1); ++i)
                extend(s[i] - 'a' , col);
        }
        inline void dfs(int u , int par)
        {
            anc[u][0] = par;
            for (int i = 1; i < MAXLOG; ++i)
                anc[u][i] = anc[anc[u][i - 1]][i - 1];
            for (multiset< int > :: iterator it = s[u].begin(); it != s[u].end(); ++it)
                SGT.modify(rt[u] , 1 , n , *it , 1);
            for (unsigned i = 0; i < a[u].size(); ++i)
            {
                int v = a[u][i];
                if (v == par) continue;
                dfs(v , u);
                rt[u] = SGT.merge(rt[u] , rt[v] , 1 , n);
            }
        }
        inline void buildtree()
        {
            for (int i = 1; i <= sz; ++i)
                a[father[i]].push_back(i);
            dfs(1 , 0);
        }
    } SAM;
    
    template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); }
    template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    
    int main()
    {
        
        scanf("%s" , s + 1);
        scanf("%d" , &n);
        for (int i = 1; i <= n; ++i)
        {
            scanf("%s" , S + 1);
            SAM.insert(S , i);
        }
        SAM.buildtree();
        m = strlen(s + 1);
        int now = 1 , L = 0;
        for (int i = 1; i <= m; ++i)
        {
            int ch = s[i] - 'a';
            if (SAM.child[now][ch])
            {
                now = SAM.child[now][ch];
                ++L;
            } else
            {
                while (now && !SAM.child[now][ch]) now = SAM.father[now];
                if (!now)
                {
                    now = 1;
                    L = 0;
                } else
                {
                    L = SAM.depth[now] + 1;
                    now = SAM.child[now][ch];
                }
            }
            pos[i] = now;
            len[i] = L;
        }
        scanf("%d" , &q);
        while (q--)
        {
            int l , r , pl , pr;
            scanf("%d%d%d%d" , &l , &r , &pl , &pr);
            if (len[pr] < pr - pl + 1)
            {
                printf("%d %d
    " , l , 0);
                continue;
            }
            int u = pos[pr];
            for (int i = MAXLOG - 1; i >= 0; i--)
                if (SAM.depth[anc[u][i]] >= pr - pl + 1) 
                    u = anc[u][i];
            pair<int , int> ans = SGT.query(rt[u] , 1 , n , l , r);
            if (!ans.first) ans.first = l;
            printf("%d %d
    " , ans.first , ans.second);
        }
        
        return 0;
    }

        

  • 相关阅读:
    微软面试100 题题解
    二元查找树转变成排序的双向链表(树)
    筆試
    PE注入
    内核网络通信
    哈哈哈
    OpenCV 学习
    第一次研究VM程序中的爆破点笔记
    SE2.3.4各试用限制调试笔记
    破解相关书籍
  • 原文地址:https://www.cnblogs.com/evenbao/p/10623875.html
Copyright © 2011-2022 走看看