题意:在传统的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; }