CF803G Periodic RMQ Problem

这题很妙,当时用CD的方法,写平衡树,但是吧没有领会精神,写了200多行,发现前驱后继又不合法的情况,好像要写12种情况,就不想写了。然后就突然明白线段树做法了。。。

介绍一种线段树做法:

本质思想是一样的,可能实现上优雅一点?

本质思想:动态开点,最多会有十万个点,完全可以,如果一段区间被覆盖一次之后,那么直接维护,如果没有被覆盖,我们需要在原序列上查询。

如果需要查询的区间在同一个周期内,直接查,如果大于一个周期,就是最小值,如果跨越两个区间,就很尴尬,可以将序列复制一遍,然后r = l + len - 1,查询。st表维护一下。会发现如果儿子没有被覆盖,那么一定是空。如果是空,那么直接查询,魔改pushup就行。

查询的话,如果说目前节点的区间为空,我们需要查询这个区间对应的原序列,左端点取max,右端点取min就行。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
const int INF = 1 << 30;
int n,k,q,b[N],rt,st[N << 1][21];
void St_pre(){
    memset(st,0x3f,sizeof(st));
    for(int i = 1;i <= n;++i)st[i][0] = b[i];
    for(int i = n + 1;i <= 2 * n;++i)st[i][0] = b[i - n];
    for(int i = 1;i <= 20;++i)for(int j = 1;j + (1 << i) - 1 <= n * 2;++j)st[j][i] = min(st[j][i - 1],st[j + (1 << (i - 1))][i - 1]);
}
int St_ask(int l,int r){
    int ed = log2(r - l + 1);
    return min(st[l][ed],st[r - (1 << ed) + 1][ed]);
}
int Ask(int l,int r){
    int len = r - l + 1;
    if(len >= n){
        return St_ask(1,n);
    }else{
        l = (l % n == 0) ? n : (l % n);
        return St_ask(l,l + len - 1);
    }
}
struct Segment{
    #define lson(p) t[p].ls
    #define rson(p) t[p].rs
    struct node{
        int ls,rs,minn,lz;
        node(){lz = 0;minn = INF;}
    }t[N * 50];
    int tot = 0;
    Segment(){tot = 0;}
    void pushup(int p,int l,int r){
        int lw = INF,rw = INF,mid = l + r >> 1;
        if(lson(p))lw = t[lson(p)].minn;
        else lw = Ask(l,mid);
        if(rson(p))rw = t[rson(p)].minn;
        else rw = Ask(mid + 1,r);
        t[p].minn = min(lw,rw);
    }
    void tag(int &p,int val){
        if(!p)p = ++tot;
        t[p].lz = val;
        t[p].minn = val;
    }
    void pushdown(int p){
        if(!t[p].lz)return;
        tag(lson(p),t[p].lz);
        tag(rson(p),t[p].lz);
        t[p].lz = 0;
    }
    void modify(int &p,int L,int R,int l,int r,int val){
        if(!p)p = ++tot;
        if(l <= L && r >= R){
            tag(p,val);
            return;
        }    
        pushdown(p);
        int mid = L + R >> 1;
        if(l <= mid)modify(lson(p),L,mid,l,r,val);
        if(r > mid)modify(rson(p),mid + 1,R,l,r,val);
        pushup(p,L,R);
    }
    int query(int p,int L,int R,int l,int r){
        if(l > r)return INF;
        if(!p)return Ask(max(l,L),min(r,R));
        if(l <= L && r >= R)return t[p].minn;
        int mid = L + R >> 1;
        pushdown(p);
        int res = 1 << 30;
        if(l <= mid)res = min(res,query(lson(p),L,mid,l,r));
        if(r > mid)res = min(res,query(rson(p),mid + 1,R,l,r));
        return res;
    }
}S;
int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>k;
    for(int i = 1;i <= n;++i)cin>>b[i];
    St_pre();
    cin>>q;
    for(int i = 1;i <= q;++i){
        int opt,l,r,x;
        cin>>opt>>l>>r;
        if(opt & 1){
            cin>>x;
            S.modify(rt,1,n * k,l,r,x);
        }else cout<<S.query(rt,1,n * k,l,r)<<"\n";
    }
    return 0;
}
posted @ 2022-11-20 18:09  zasdcn  阅读(22)  评论(0编辑  收藏  举报