UVA - 12299 RMQ with Shifts (线段树:单点修改,区间查询)

题意:在传统的RMQ的基础上加上一个操作:shift(i1,i2,i3...ik),表示将这些元素,依次向左移动一位

思路:在原先线段树的基础上再加上:首先要先得到该位的数字,那么就是在[i,i]的区间找最小值,然后将该位置的值修改为后一位

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100010;
const int INF = 0x3f3f3f3f;

int n,m,a[MAXN<<2];
int q[33],tmp[33];
char str[33];

void build(int l,int r,int c){
    if (l == r){
        scanf("%d",&a[c]);
        return;
    }
    int mid = (l+r) >> 1;
    build(l,mid,c<<1);
    build(mid+1,r,c<<1|1);
    a[c] = min(a[c<<1],a[c<<1|1]);
}

void update(int l,int r,int p,int d,int c){
    if (l == r){
        a[c] = d;
        return;
    }
    int mid = (l+r) >> 1;
    if (p <= mid)
        update(l,mid,p,d,c<<1);
    else update(mid+1,r,p,d,c<<1|1);
    a[c] = min(a[c<<1],a[c<<1|1]);
}

int query(int l,int r,int ll,int rr,int c){
   int mid = l + (r-l) / 2,ans = INF;
   if (ll <= l && rr >= r)
       return a[c];
   if (ll <= mid)
       ans = min(ans,query(l,mid,ll,rr,c<<1));
   if (rr > mid)
       ans = min(ans,query(mid+1,r,ll,rr,c<<1|1));
   return ans;
}

void solve(){
    int sp = 6;
    int cnt = 0;
    while (1){
        int tot = 0;
        while (str[sp] >= '0' && str[sp] <= '9')
            tot = tot*10 + (str[sp++] - '0');
        q[cnt++] = tot;
        if (str[sp] == ',')
            sp++;
        else break;
    }
    if (str[0] == 's'){
        for (int i = 0; i < cnt; i++)
            tmp[i] = query(1,n,q[i],q[i],1);
        for (int i = 0; i < cnt; i++)
            update(1,n,q[i],tmp[(i+1)%cnt],1);
    }
    else printf("%d\n",query(1,n,q[0],q[1],1));
}

int main(){
    scanf("%d%d",&n,&m);
    build(1,n,1);
    while (m--){
        scanf("%s",str);
        solve();
    }
    return 0;
}



你可能感兴趣的:(UVA - 12299 RMQ with Shifts (线段树:单点修改,区间查询))