CF803G - 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\n", 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\n",query(getid(ask[i].le), getid(ask[i].ri), 1, N, 1));
                }
            }
            return 0;
}
View Code

 

转载于:https://www.cnblogs.com/ckxkexing/p/11203490.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值