• Luogu P4585 【[FJOI2015]火星商店问题】


    Description

    传送门


    Solution

    其实这题是没有必要使用可持久化(Trie)的。

    首先建立一颗线段树,每个节点维护它所代表的那些商店的商品的标价所构成的(Trie)

    这样如果没有时间上的限制,我们可以将每次的询问拆成对于(log(n))个线段树上的节点的询问,每次在(Trie)上花费(log(w))的时间复杂度查询最大值,然后对所有答案取(max)即为所求答案。

    注意这里时间的限制是一个后缀,也就是说是从某个历史节点延续的目前节点的,那么可以对于每个(Trie)上的点记录最后遍历到的时间,这样(d)时间以前的就是记录的时间(<)目前时间(- d + 1)的节点。这些节点实际上在(Trie)上式没有的,在查询的时候直接将它们忽略即可。

    对于每个商店的特殊商品,将它们最后遍历到的时间赋值为(INF)即可,这些特殊商品的存在也保证了每哥询问一定有解。

    综上,由于(n)(w)同级,时间复杂度为(O(log^2n)),空间复杂度为(O(log^2n))


    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    const int N = 100000;
    const int INF = 0x7fffffff;
    
    int n, m, root[(N << 2) + 50], num, tim[30000050], trie[30000050][2], cnt;
    
    void Read(int &x)
    {
        x = 0; int p = 0; char st = getchar();
        while (st < '0' || st > '9') p = (st == '-'), st = getchar();
        while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
        x = p ? -x : x;
        return;
    }
    
    void Insert(int &root, int val, int id)
    {
        if (!root) root = ++num;
        int now = root;
        for (int i = 17; i >= 0; i--)
        {
            int c = ((val >> i) & 1);
            if (!trie[now][c]) trie[now][c] = ++num;
            now = trie[now][c]; tim[now] = max(tim[now], id);
        } 
        return;
    }
    
    int Ans(int root, int val, int id)
    {
        int ans = 0, now = root;
        for (int i = 17; i >= 0; i--)
        {
            int c = ((val >> i) & 1);
            if (trie[now][c ^ 1] && tim[trie[now][c ^ 1]] >= cnt - id + 1) 
                now = trie[now][c ^ 1], ans = ans + (1 << i);
            else now = trie[now][c];
        }
        return ans;
    }
    
    void Change(int k, int l, int r, int pos, int val, int tim)
    {
        Insert(root[k], val, tim);
        if (l == r) return; 
        int mid = (l + r) >> 1;
        if (pos <= mid) Change(k << 1, l, mid, pos, val, tim);
        else Change(k << 1 | 1, mid + 1, r, pos, val, tim);
        return;
    }
    
    int Query(int k, int l, int r, int x, int y, int val, int tim)
    {
        if (x <= l && r <= y) return Ans(root[k], val, tim);
        int mid = (l + r) >> 1;
        if (y <= mid) return Query(k << 1, l, mid, x, y, val, tim);
        else if (x > mid) return Query(k << 1 | 1, mid + 1, r, x, y, val, tim);
        else return max(Query(k << 1, l, mid, x, y, val, tim), Query(k << 1 | 1, mid + 1, r, x, y, val, tim));
    }
    
    int main()
    {
        Read(n); Read(m);
        for (int i = 1, x; i <= n; i++) Read(x), Change(1, 1, n, i, x, INF);
        int p, l, r, x, d, s, val;
        while (m--)
        {
            Read(p);
            if (p)
            {
                Read(l); Read(r); Read(x); Read(d);
                printf("%d
    ", Query(1, 1, n, l, r, x, d));
            }
            else
            {
                cnt++;
                Read(s); Read(val);
                Change(1, 1, n, s, val, cnt);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    SpringBoot中添加事务
    隐藏样式
    Mybatis配置解析
    题目1064:反序数------玩转小聪明
    题目1063:整数和
    题目1062:分段函数23333333333333
    题目1060:完数VS盈数------这题做得我想骂人
    题目1059:abc----------就喜欢这样的题
    题目1050:完数-----------runtime error的问题
    题目1049:字符串去特定字符
  • 原文地址:https://www.cnblogs.com/Tian-Xing-Sakura/p/13404245.html
Copyright © 2020-2023  润新知