zoukankan      html  css  js  c++  java
  • 2016集训测试赛(二十)Problem B: 字典树

    Description

    题目大意

    你们自己感受一下原题的画风...
    我怀疑出题人当年就是语文爆零的
    下面复述一下出题人的意思:

    • 操作1: 给你一个点集, 要你在trie上找到所有这样的点, 满足点集中存在某个点所表示的字符串是这个点所表示字符串的后缀. 把这些点的权值加一;
    • 操作2: 给你一个点集, 要你在trie上找到所有这样的点, 满足这个点所表示的字符串是点集中某个点的后缀; 求所有这些点的权值之和.

    做法很显然, 我们先建立出后缀树, 在后缀树上树剖, 剖出的序列用线段树维护即可.
    注意树剖得到的序列中, 一个点所表示的子树是连在一起的, 因此可以直接修改子树.

    Solution

    后缀自动机上树剖.
    题目描述根本就不可看

    #include <cstdio>
    #include <cctype>
    #include <deque>
    #include <cstring>
    #include <vector>
    #include <algorithm>
     
    using namespace std;
    namespace Zeonfai
    {
        inline int getInt()
        {
            int a = 0, sgn = 1; char c;
            while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
            while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
            return a * sgn;
        }
        inline int getChar()
        {
            char c; while(! isgraph(c = getchar())); return c;
        }
        inline void print(int a) {if(! a) return; print(a / 10); putchar('0' + a % 10);}
        inline void println(int a)
        {
            if(a < 0) putchar('-'); if(! a) putchar('0');
            print(a);
            putchar('
    ');
        }
    }
    const int N = (int)1e5;
    int tp;
    struct segmentTree
    {
        struct node
        {
            int tg, sz;
            long long sum;
        }nd[N << 2 << 2];
        inline segmentTree() {memset(nd, 0, sizeof(nd));}
        void addSize(int u, int L, int R, int pos)
        {
            ++ nd[u].sz;
            if(L == R) return;
            if(pos <= L + R >> 1) addSize(u << 1, L, L + R >> 1, pos); else addSize(u << 1 | 1, (L + R >> 1) + 1, R, pos);
        }
        inline void addSize(int pos) {addSize(1, 0, tp - 1, pos);}
        inline void pushDown(int u)
        {
            nd[u << 1].tg += nd[u].tg; nd[u << 1].sum += nd[u << 1].sz * nd[u].tg;
            nd[u << 1 | 1].tg += nd[u].tg; nd[u << 1 | 1].sum += nd[u << 1 | 1].sz * nd[u].tg;
            nd[u].tg = 0;
         }
        void modify(int u, int curL, int curR, int L, int R, int x)
        {
            if(curL >= L && curR <= R) {nd[u].tg += x; nd[u].sum += nd[u].sz * x; return;}
            pushDown(u);
            int mid = curL + curR >> 1;
            if(L <= mid) modify(u << 1, curL, mid, L, R, x);
            if(R > mid) modify(u << 1 | 1, mid + 1, curR, L, R, x);
            nd[u].sum = nd[u << 1].sum + nd[u << 1 | 1].sum;
        }
        inline void modify(int L, int R, int x) {modify(1, 0, tp - 1, L, R, x);}
        long long query(int u, int curL, int curR, int L, int R)
        {
            if(curL >= L && curR <= R) return nd[u].sum;
            pushDown(u);
            int mid = curL + curR >> 1; long long res = 0;
            if(L <= mid) res += query(u << 1, curL, mid, L, R);
            if(R > mid) res += query(u << 1 | 1, mid + 1, curR, L, R);
            return res;
        }
        long long query(int L, int R) {return query(1, 0, tp - 1, L, R);}
    }seg;
    struct node
    {
        int suc[26], pre, len, isReal;
        int vst;
        vector<int> successorOnSuffixTree;
        int sz, hvy, dep, tp, id, L, R;
        inline node() {memset(suc, -1, sizeof(suc)); pre = -1; vst = isReal = 0; successorOnSuffixTree.clear();}
    }nd[N << 2];
    inline int cmp(int a, int b) {return nd[a].id < nd[b].id;}
    struct suffixAutomaton
    {
        int rt;
        inline suffixAutomaton() {tp = 1; rt = 0; nd[rt].isReal = 1;}
        inline int insert(int lst, int c)
        {
            int u = tp ++; nd[u].len = nd[lst].len + 1; nd[u].isReal = 1;
            for(; ~ lst && nd[lst].suc[c] == -1; lst = nd[lst].pre) nd[lst].suc[c] = u;
            if(lst == -1) nd[u].pre = rt;
            else
            {
                int p = nd[lst].suc[c];
                if(nd[p].len == nd[lst].len + 1) nd[u].pre = p;
                else
                {
                    int q = tp ++; nd[q].len = nd[lst].len + 1; nd[q].pre = nd[p].pre; for(int i = 0; i < 26; ++ i) nd[q].suc[i] = nd[p].suc[i]; //保险起见, 这里不要整个复制
                    nd[p].pre = nd[u].pre = q;
                    for(; ~ lst && nd[lst].suc[c] == p; lst = nd[lst].pre) nd[lst].suc[c] = q;
                }
            }
            return u;
        }
        void build(int u)
        {
            if(~ nd[u].pre) nd[nd[u].pre].successorOnSuffixTree.push_back(u); nd[u].vst = 1;
            for(int i = 0; i < 26; ++ i) if(~ nd[u].suc[i] && ! nd[nd[u].suc[i]].vst) build(nd[u].suc[i]);
        }
        void getSize(int u)
        {
            nd[u].sz = 1; nd[u].hvy = -1;
            nd[u].dep = ~ nd[u].pre ? nd[nd[u].pre].dep + 1 : 0;
            for(auto v : nd[u].successorOnSuffixTree)
            {
                getSize(v); nd[u].sz += nd[v].sz;
                if(nd[u].hvy == -1 || nd[v].sz > nd[nd[u].hvy].sz) nd[u].hvy = v;
            }
        }
        int clk;
        void decomposition(int u, int tp)
        {
            nd[u].L = nd[u].id = clk ++; nd[u].tp = tp; if(nd[u].isReal) seg.addSize(nd[u].id);
            if(~ nd[u].hvy) decomposition(nd[u].hvy, tp);
            for(auto v : nd[u].successorOnSuffixTree) if(v != nd[u].hvy) decomposition(v, v);
            nd[u].R = clk - 1;
        }
        inline void build() {build(rt); getSize(rt); clk = 0; decomposition(rt, rt);}
        inline int getLCA(int u, int v)
        {
            while(nd[u].tp != nd[v].tp)
            {
                if(nd[nd[u].tp].dep > nd[nd[v].tp].dep) u = nd[nd[u].tp].pre;
                else if(nd[nd[u].tp].dep < nd[nd[v].tp].dep) v = nd[nd[v].tp].pre;
                else u = nd[nd[u].tp].pre, v = nd[nd[v].tp].pre;
            }
            return nd[u].dep < nd[v].dep ? u : v;
        }
        inline long long query(int u)
        {
            long long res = 0;
            for(; ~ u; u = nd[nd[u].tp].pre) res += seg.query(nd[nd[u].tp].id, nd[u].id);
            return res;
        }
        inline void modify(int *st, int sz)
        {
            if(! sz) return;
            sort(st, st + sz, cmp);
            seg.modify(nd[st[0]].L, nd[st[0]].R, 1);
            for(int i = 1, p = 0; i < sz; ++ i) if(nd[st[i]].id > nd[st[p]].R)
                seg.modify(nd[st[i]].L, nd[st[i]].R, 1), p = i;
        }
        inline long long query(int *st, int sz)
        {
            if(! sz) return 0;
            sort(st, st + sz, cmp);
            long long ans = 0;
            ans = query(st[0]);
            for(int i = 1; i < sz; ++ i) ans += query(st[i]) - query(getLCA(st[i], st[i - 1]));
            return ans;
        }
    }SAM;
    struct trieTree
    {
        struct node
        {
            int suc[26], mp;
            inline node() {memset(suc, -1, sizeof(suc));}
        }nd[N + 1];
        inline void addEdge(int u, int c, int v) {nd[u].suc[c] = v; }
        inline void buildSuffixAutomaton()
        {
            deque<int> que; que.clear(); que.push_back(1); nd[1].mp = 0;
            for(; ! que.empty(); que.pop_front())
            {
                int u = que.front();
                for(int i = 0; i < 26; ++ i) if(~ nd[u].suc[i]) nd[nd[u].suc[i]].mp = SAM.insert(nd[u].mp, i), que.push_back(nd[u].suc[i]);
            }
        }
    }trie;
    int main()
    {
     
        #ifndef ONLINE_JUDGE
     
        freopen("trie.in", "r", stdin);
        freopen("trie.out", "w", stdout);
     
        #endif
     
        using namespace Zeonfai;
        int n = getInt();
        for(int i = 2; i <= n; ++ i)
        {
            int u = getInt(), c = getChar() - 'a';
            trie.addEdge(u, c, i);
        }
        trie.buildSuffixAutomaton();
        SAM.build();
        int m = getInt();
        for(int i = 0; i < m; ++ i)
        {
            int opt = getInt(), sz = getInt();
            static int st[N];
            for(int i = 0; i < sz; ++ i) st[i] = trie.nd[getInt()].mp;
            if(opt == 1) SAM.modify(st, sz);
            if(opt == 2) println(SAM.query(st, sz));
        }
    }
    
  • 相关阅读:
    jdbc之存储过程的调用和调用方法
    jdbc之Statement和Preparement
    jdbc之连接Oracle的基本步骤
    Oracle之子程序(存储过程、方法、包)
    Oracle之plsql及游标
    Oracle之多表查询
    Oracle之单表查询及常用函数
    Oracle之基础操作
    IO流之字符流
    IO流之字节流
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7489899.html
Copyright © 2011-2022 走看看