zoukankan      html  css  js  c++  java
  • [CF 803G]- Periodic RMQ Problem 动态开点线段树 或 离线

    CF

    题意

    有一个长度为n × k (<=1E9)的数组,有区间修改和区间查询最小值的操作。

    思路

    由于数组过大,直接做显然不行。

    有两种做法,可以用动态开点版本的线段树,或者离线搞(还没搞)(搞好了)。

    注意只有1E5次操作,所以真正被更新到的区间并不多,最差单次新开2×log(1E9)。

    对于新开的区间的最小值,可以这样计算,如果区间表示的值大于n,那就是原来长度为n的区间的最小值,小于n的话,在ST表中查询即可。

    #include <bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define fi first
    #define se second
    #define debug(x) cerr<<#x << " := " << x << endl;
    #define bug cerr<<"-----------------------"<<endl;
    #define FOR(a, b, c) for(int a = b; a <= c; ++ a)
    
    typedef long long ll;
    typedef long double ld;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    
    
    template<class T> void _R(T &x) { cin >> x; }
    void _R(int &x) { scanf("%d", &x); }
    void _R(ll &x) { scanf("%lld", &x); }
    void _R(double &x) { scanf("%lf", &x); }
    void _R(char &x) { scanf(" %c", &x); }
    void _R(char *x) { scanf("%s", x); }
    void R() {}
    template<class T, class... U> void R(T &head, U &... tail) { _R(head); R(tail...); }
    
    
    template<typename T>
    inline T read(T&x){
        x=0;int f=0;char ch=getchar();
        while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x=f?-x:x;
    }
    
    const int inf = 0x3f3f3f3f;
    
    const int mod = 1e9+7;
    
    /**********showtime************/
    
                const int maxn = 1e5+9;
                int b[maxn];
    
                int st[maxn][22], Log[maxn];
                void init_st(int n) {
                    Log[0] = -1;
                    for(int i=1; i<=n; i++) {
                        Log[i] = Log[i>>1] + 1;
                        st[i][0] = b[i];
                    }
                    for(int j=1; (1<<j) <= n; j++) {
                        for(int i=1; i + (1<<j) -1 <= n; i++) {
                            st[i][j] = min(st[i][j-1], st[i+ (1<<(j-1))][j-1]);
                        }
                    }
                }
                int rmq_st(int L, int R) {
                    int k = Log[R - L + 1];
                    return min(st[L][k], st[R-(1<<k)+1][k]);
                }
                int n,k;
                int getmin(int le, int ri) {
                    if(ri - le + 1 >= n) return rmq_st(1, n);
                    int L = le % n; if(L == 0) L = n;
                    int R = ri % n; if(R == 0) R = n;
                    if(L <= R) return rmq_st(L, R);
                    return min(rmq_st(L, n), rmq_st(1, R));
                }
                struct Node{
                    int le, ri;
                    int lc,rc;
                    int val, tag;
                } tree[maxn * 60];
                int tot = 0;
                int newNode(int le, int ri) {
                    tot++;
                    tree[tot].le = le;
                    tree[tot].ri = ri;
                    tree[tot].lc =  tree[tot].rc = 0;
                    tree[tot].val = getmin(le, ri);
                    tree[tot].tag = 0;
                    return tot;
                }
                void pushdown(int rt) {
                    tree[tree[rt].lc].val = tree[tree[rt].lc].tag = tree[rt].tag;
                    tree[tree[rt].rc].val = tree[tree[rt].rc].tag = tree[rt].tag;
                    tree[rt].tag = 0;
                }
                void update(int L, int R, int b, int rt) {
                    if(L<=tree[rt].le && tree[rt].ri <= R) {
                        tree[rt].val = tree[rt].tag = b;
                        return;
                    }
                    int mid = (tree[rt].le + tree[rt].ri) >> 1;
                    if(tree[rt].lc == 0) tree[rt].lc = newNode(tree[rt].le, mid);
                    if(tree[rt].rc == 0) tree[rt].rc = newNode(mid+1, tree[rt].ri);
                    if(tree[rt].tag) pushdown(rt);
                    if(mid >= L) update(L, R, b, tree[rt].lc);
                    if(mid < R) update(L, R, b, tree[rt].rc);
                    tree[rt].val = min(tree[tree[rt].lc].val, tree[tree[rt].rc].val);
                }
                int query(int L, int R, int rt) {
                    if(L <= tree[rt].le && tree[rt].ri <= R) {
                        return tree[rt].val;
                    }
    
                    int mid = (tree[rt].le + tree[rt].ri) >> 1;
                    if(tree[rt].lc == 0) tree[rt].lc = newNode(tree[rt].le, mid);
                    if(tree[rt].rc == 0) tree[rt].rc = newNode(mid+1, tree[rt].ri);
                    if(tree[rt].tag) pushdown(rt);
                    int res = inf;
                    if(mid >= L) res = min(res, query(L, R, tree[rt].lc));
                    if(mid < R) res = min(res, query(L, R, tree[rt].rc));
                    tree[rt].val = min(tree[tree[rt].lc].val, tree[tree[rt].rc].val);
                    return res;
                }
    int main(){
                scanf("%d%d", &n, &k);
                for(int i=1; i<=n; i++) scanf("%d", &b[i]);
                init_st(n);
                int q;  scanf("%d", &q);
                newNode(1, n * k);
                while(q--) {
                    int op;
                    scanf("%d", &op);
                    if(op == 1) {
                        int le,ri,x;
                        scanf("%d%d%d", &le, &ri, &x);
                        update(le, ri, x, 1);
                    }
                    else {
                        int le, ri;
                        scanf("%d%d", &le, &ri);
                        printf("%d
    ", query(le, ri, 1));
                    }
                }
                return 0;
    }
    View Code

    离线的话,我们可以记录下所有被问到的点,然后我们可以压缩原来长度为1E9的数组:问到的点保持不变,而相邻两点之间的区间压缩成一个点,保存这段区间的最小值即可。

    #include <iostream>
    #include <vector>
    #include <queue>
    #include <algorithm>
    using namespace std;
    #define pb push_back
    #define fi first
    #define se second
    #define debug(x) cerr<<#x << " := " << x << endl;
    #define bug cerr<<"-----------------------"<<endl;
    #define FOR(a, b, c) for(int a = b; a <= c; ++ a)
    
    typedef long long ll;
    typedef long double ld;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    
    
    template<class T> void _R(T &x) { cin >> x; }
    void _R(int &x) { scanf("%d", &x); }
    void _R(ll &x) { scanf("%lld", &x); }
    void _R(double &x) { scanf("%lf", &x); }
    void _R(char &x) { scanf(" %c", &x); }
    void _R(char *x) { scanf("%s", x); }
    void R() {}
    template<class T, class... U> void R(T &head, U &... tail) { _R(head); R(tail...); }
    
    
    template<typename T>
    inline T read(T&x){
        x=0;int f=0;char ch=getchar();
        while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x=f?-x:x;
    }
    
    const int inf = 0x3f3f3f3f;
    
    const int mod = 1e9+7;
    
    /**********showtime************/
    
                const int maxn = 1e5+9;
                int b[maxn];
                struct Query{
                    int op;
                    int le,ri;
                    int x;
                } ask[maxn];
                vector<int>v, nv,node;
                
                int n,k; 
                int st[maxn][20];
                int Log[maxn];
    
                void init_st(int n){
                    Log[0] = -1;
                    for(int i = 1; i<=n; i++) {
                        st[i][0] = b[i];
                        Log[i] = Log[i>>1] + 1;
                    }
    
                    for(int j=1; (1<<j) <= n; j++) {
                        for(int i=1; i + (1 << j) -1 <= n; i ++) {
                            st[i][j] = min(st[i][j-1], st[i + (1<<(j-1)) ][j-1]);
                        }
                    }
                }
                int get(int L, int R) {
                    int k = Log[R - L + 1];
                    return min(st[L][k], st[R-(1<<k)+1][k]);
                }
                int getmin(int le, int ri) {
                    if(ri - le + 1>= n) 
                        return get(1, n);
                    int l = le % n; if(!l) l = n;
                    int r = ri % n; if(!r) r = n;
                    if(l <= r) return get(l, r);
                    return min(get(l, n), get(1, r));
                }
                
                int getid(int val) {
                    return lower_bound(nv.begin(), nv.end(), val) - nv.begin() + 1;
                }
                
                int mn[maxn*16],lazy[maxn * 16];
                void build(int le, int ri, int rt) {
                    if(le == ri) {
                        mn[rt] = node[le-1];
                        return;
                    }
                    int mid = (le + ri) >> 1;
                    build(le, mid, rt<<1);
                    build(mid+1, ri, rt<<1|1);
                    mn[rt] = min(mn[rt<<1], mn[rt<<1|1]);
                }
                void pushdown(int rt) {
                    mn[rt<<1] = mn[rt<<1|1] = lazy[rt];
                    lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
                    lazy[rt] = 0;
                }
                void update(int L, int R,int x, int le, int ri, int rt) {
                    if(le >= L && ri <= R){
                        lazy[rt] = x;
                        mn[rt] = x;
                        return ;
                    }
                    if(lazy[rt]) pushdown(rt);
                    int mid = (le + ri) >> 1;
                    if(mid >= L) update(L, R, x, le, mid, rt<<1);
                    if(mid < R) update(L, R, x, mid+1, ri, rt<<1|1);
                    mn[rt] = min(mn[rt<<1], mn[rt<<1|1]);
                }
                int query(int L, int R,int le, int ri, int rt) {
                    if(le >= L && ri <= R) {
                        return mn[rt];
                    }
                    if(lazy[rt]) pushdown(rt);
                    int mid = (le + ri) >> 1;
                    int res = inf;
                    if(mid >= L) res = min(res, query(L, R, le, mid, rt<<1));
                    if(mid < R) res = min(res, query(L, R, mid+1,ri, rt<<1|1));
                    mn[rt] = min(mn[rt<<1], mn[rt<<1|1]);
                    return res;
                }
    int main(){
                scanf("%d%d", &n, &k);
                for(int i=1; i<=n; i++) scanf("%d", &b[i]);
                init_st(n);
                int q;  scanf("%d", &q);
                for(int i=1; i<=q; i++){
                    int op;
                    scanf("%d", &op);
                    if(op == 1) {
                        ask[i].op = op;
                        scanf("%d%d%d", &ask[i].le, &ask[i].ri, &ask[i].x);
                        v.pb(ask[i].le);
                        v.pb(ask[i].ri);
                    }
                    else{
                        ask[i].op = op;
                        scanf("%d%d", &ask[i].le, &ask[i].ri);
                        v.pb(ask[i].le);
                        v.pb(ask[i].ri);
                    }
                }
                sort(v.begin(), v.end());
                v.erase(unique(v.begin(), v.end()), v.end());
                int N = v.size();
                // cout<<" ** "<<endl;
                for(int i=0; i<N; i++) {
                    node.pb( getmin(v[i],v[i]));
                    nv.pb(v[i]);
                    if(i+1 < N && v[i] + 1 <= v[i+1] - 1) 
                    {
                        node.pb(getmin(v[i]+1, v[i+1]-1));
                        nv.pb(v[i]+1);
                    }
                }   
    
                /// 把一个开区间当成一个点。
                
                N = nv.size();
                build(1, N, 1);
                for(int i=1; i<=q; i++) {
                    if(ask[i].op == 1) {
                        update(getid(ask[i].le),getid(ask[i].ri), ask[i].x, 1, N, 1);
                    }   
                    else {
                        printf("%d
    ",query(getid(ask[i].le), getid(ask[i].ri), 1, N, 1));
                    }
                }
                return 0;
    }
    View Code
  • 相关阅读:
    尾递归
    博客搬家 --- CSDN
    sublime text 插件集锦
    chrome 常用插件集锦
    IntelliJ Idea 2017 免费激活方法
    Mac下Java JNI 调C
    webgl学习笔记五-纹理
    webgl学习笔记四-动画
    webgl学习笔记三-平移旋转缩放
    webgl学习笔记二-绘图多点
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/11203490.html
Copyright © 2011-2022 走看看