题目大意:第一行输入两个整数(数据个数,操作个数),query(a,b)为查找区间a到b的最小值,并输出。shift(a,b,c,d...)为将a,b,c,d...全部循环左移。
解析:线段树的单点更新。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctype.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 100005;
int L[N << 2],R[N << 2],s[N << 2];
int a[N],d[N];
void build(int u,int l,int r) {
if(l == r) { //当前是叶节点
L[u] = R[u] = l;
s[u] = a[l];
return;
}
//非叶节点
int mid = (l + r) / 2;
build(u*2,l,mid);
build(u*2+1,mid+1,r);
L[u] = l;
R[u] = r;
s[u] = min(s[u*2],s[u*2+1]);
}
void modify(int u,int x,int v) {
if(x == L[u] && x == R[u]) {
s[u] = v;
return;
}
int mid = (L[u] + R[u]) / 2;
if(mid >= x) {
modify(u*2,x,v);
}else {
modify(u*2+1,x,v);
}
s[u] = min(s[u*2],s[u*2+1]);
}
int query(int u,int l,int r) {
if(l <= L[u] && R[u] <= r) {
return s[u];
}
int mid = (L[u] + R[u]) / 2;
int ret = INF;
if(l <= mid) {
ret = min(ret, query(u*2,l,r));
}
if(r > mid) {
ret = min(ret, query(u*2+1,l,r));
}
return ret;
}
char cmd[1000];
int read_line(char cmd[]) {
int len = strlen(cmd);
int tot = 0;
int num = 0;
for(int i = 6; i < len; i++) {
if(isalnum(cmd[i])) {
num = num * 10 + (cmd[i] - '0');
}else {
d[tot++] = num;
num = 0;
}
}
return tot;
}
int main() {
int n,q;
while(scanf("%d%d",&n,&q) != EOF) {
for(int i = 1; i <= n; i++) {
scanf("%d",&a[i]);
}
memset(s,0,sizeof(s));
L[1] = 1;
R[1] = n;
build(1,L[1],R[1]);
while(q--) {
scanf("%s",cmd);
if(cmd[0] == 'q') {
int l,r;
sscanf(cmd,"query(%d,%d)",&l,&r);
printf("%d\n",query(1,l,r));
}else {
int tot = read_line(cmd);
int tmp = a[d[0]];
for(int i = 1; i < tot; i++) {
modify(1,d[i-1],a[d[i]]);
a[d[i-1]] = a[d[i]];
}
modify(1,d[tot-1],tmp);
a[d[tot-1]] = tmp;
}
}
}
return 0;
}