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
  • 相关阅读:
    Mysql登录错误:ERROR 1045 (28000): Plugin caching_sha2_password could not be loaded
    Docker配置LNMP环境
    Docker安装mysqli扩展和gd扩展
    Docker常用命令
    Ubuntu常用命令
    单例模式的优缺点和使用场景
    ABP 多租户数据共享
    ABP Core 后台Angular+Ng-Zorro 图片上传
    ERROR Error: If ngModel is used within a form tag, either the name attribute must be set or the form control must be defined as 'standalone' in ngModelOptions.
    AbpCore 执行迁移文件生成数据库报错 Could not find root folder of the web project!
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/11203490.html
Copyright © 2011-2022 走看看