• 题解-CF803G Periodic RMQ Problem


    (Large exttt{CF803G})

    标签:线段树、离散化

    可能就是码量大了一点

    题意

    这么清楚了就不作赘述了QwQ

    就是要注意它的 ( exttt{q}) 大小只有 (1e5)

    思路

    面对这种题目,串的长度很长但是有规律,区间修改为赋值操作,基本上都有一个十分套路的通解,因为对于 (1e5) 的操作数据访问很少,操作只要记录两个端点,所以有些元素根本不会用到它,把它们忽视掉就好了,可以用离散化优化。

    但是这里的串初始化时一段串重复多次形成的,可能有点难离散化,我的方法是把所有操作两个端点离散化下来,对于每两个端点间的区间(不包括这两个端点)也离散化成一个值,这个值就是区间中最小的数。

    这个区间的值可以分类得到:

    1. 区间的两个端点距离超过一个序列 (a) 的长度,那么直接将这个区间的值取为序列a的最小值。

    2. 区间的两个端点在完整的一个 (a) 序列内,这里可以把它们相对于a序列的位置求出来,用 ( exttt{ST}) 表求出区间最小值。

    3. 区间的两个端点跨越了一个序列 (a) ,这可以把两端区间(端点 (r) 到序列头,端点 (l) 序列尾)的最小值,同样用 ( exttt{ST}) 表做到 (O(1)) 查询。

    然后维护好所有的端点后,剩下的操作用朴素的线段树就可以过去。

    复杂度 ( exttt{O(玄学+可过)})

    目前的最优解 (3.37ms)

    代码

    
    #include <bits/stdc++.h>
    using namespace std;
    
    #define ls n << 1
    #define rs n << 1 | 1
    const int N = 1e5;
    inline int read()
    {
        register int s = 0;
        register bool neg = 0;
        register char c = getchar();
        for (; c < '0' || c > '9'; c = getchar())
            neg |= (c == '-');
        for (; c >= '0' && c <= '9'; s = s * 10 + (c ^ 48), c = getchar())
            ;
        return (neg ? -s : s);
    }
    
    int a, b, c, s[N + 10], p[(N << 1) + 10], top, q[(N << 2) + 10], id, f[N + 10][30];
    struct ask
    {
        int opt, l, r, x;
    } ask[N + 10];
    struct Stree
    {
        int l, r, mn;
        bool lazy;
    } t[(N << 4) + 10];
    struct reel_id
    {
        int id, val;
    } o[(N << 1) + 10];
    
    inline int find(int n)
    {
        int l = 1, r = top;
        while (l <= r)
        {
            int mid = (l + r) >> 1;
            if (o[mid].val == n)
                return o[mid].id;
            if (o[mid].val < n)
                l = mid + 1;
            else
                r = mid - 1;
        }
    }
    
    inline int query(int l, int r)//ST表O(1)询问
    {
        int k = log2(r - l + 1);
        return min(f[l][k], f[r - (1 << k) + 1][k]);
    }
    
    inline void up(int n)
    {
        t[n].mn = min(t[ls].mn, t[rs].mn);
    }
    
    inline void down(int n)
    {
        if (!t[n].lazy)
            return;
        t[ls].mn = t[rs].mn = t[n].mn;
        t[ls].lazy = t[rs].lazy = 1;
        t[n].lazy = 0;
    }
    
    inline void build(int n, int l, int r)
    {
        t[n].l = l;
        t[n].r = r;
        t[n].mn = 1e9;
        if (l == r)
        {
            t[n].mn = q[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(ls, l, mid);
        build(rs, mid + 1, r);
        up(n);
    }
    
    inline void change(int n, int l, int r, int k)
    {
        if (l <= t[n].l && t[n].r <= r)
        {
            t[n].mn = k;
            t[n].lazy = 1;
            return;
        }
        down(n);
        int mid = (t[n].l + t[n].r) >> 1;
        if (l <= mid)
            change(ls, l, r, k);
        if (mid < r)
            change(rs, l, r, k);
        up(n);
    }
    
    inline int Query(int n, int l, int r)
    {
        if (l <= t[n].l && t[n].r <= r)
            return t[n].mn;
        int mid = (t[n].l + t[n].r) >> 1, sum = 1e9;
        down(n);
        if (l <= mid)
            sum = min(sum, Query(ls, l, r));
        if (mid < r)
            sum = min(sum, Query(rs, l, r));
        return sum;
    }
    
    signed main()
    {
        a = read();
        b = read();
        int mn = 1e9;
        for (int i = 1; i <= a; i++)
            s[i] = f[i][0] = read(), mn = min(mn, s[i]);
        for (int i = 1; i <= 25; i++)
            for (int j = 1; j + (1 << i) - 1 <= a; j++)
                f[j][i] = min(f[j][i - 1], f[j + (1 << (i - 1))][i - 1]);
        c = read();
        for (int i = 1; i <= c; i++)
        {
            ask[i].opt = read();
            ask[i].l = read();
            ask[i].r = read();
            if (ask[i].opt == 1)
                ask[i].x = read();
            p[++top] = ask[i].l;
            p[++top] = ask[i].r;
        }
        sort(p + 1, p + top + 1);//离散下询问的所有端点 
        top = unique(p + 1, p + top + 1) - p - 1;
        for (int i = 1; i <= top; i++)
        {
            if (i > 1 && p[i] - p[i - 1] > 1)//离散下区间 
            {
                int l = p[i - 1] + 1, r = p[i] - 1;
                if (r - l + 1 >= a)
                    q[++id] = mn;
                else
                {
                    l = (l - 1) % a + 1;
                    r = (r - 1) % a + 1;
                    if (l <= r)
                        q[++id] = query(l, r);
                    else
                        q[++id] = min(query(1, r), query(l, a));
                }
            }
            q[++id] = s[(p[i] - 1) % a + 1];
            o[i].val = p[i];
            o[i].id = id;
        }
        for (int i = 1; i <= c; i++)
            ask[i].l = find(ask[i].l), ask[i].r = find(ask[i].r);//修改下操作的两个端点 
        build(1, 1, id);
        for (int i = 1; i <= c; i++)
        {
            if (ask[i].opt == 1)
                change(1, ask[i].l, ask[i].r, ask[i].x);
            if (ask[i].opt == 2)
                printf("%d
    ", Query(1, ask[i].l, ask[i].r));
        }
        return 0;
    }
    
  • 相关阅读:
    查找算法(I) 顺序查找 二分查找 索引查找
    快速排序 Quick Sort
    Activity生命周期
    Android中资源文件的使用
    排序算法
    插入排序(I)Insert Sort
    Java eclipse调试技巧什么的。。
    HTTP协议解析
    python技巧26[str+unicode+codecs]
    python类库26[PySide之helloworld]
  • 原文地址:https://www.cnblogs.com/RedreamMer/p/13815531.html
Copyright © 2020-2023  润新知