• 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));
        }
    }
    
  • 相关阅读:
    Web 性能优化
    js 校验身份证
    html5 输入框响应enter按键
    获取浏览器的可视窗口宽高
    js打开新标签
    Java数据脱敏框架
    Spring Boot中的事务管理
    运维监控知识体系
    git常用命令图解 & 常见错误
    安全团队不可错过的七个云安全开源工具(转载)
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7489899.html
Copyright © 2020-2023  润新知