uva 12299 - RMQ with Shifts(线段树)

942 篇文章 2 订阅

题目链接:uva 12299 - RMQ with Shifts

题目大意:给定一个数组,有两种操作。

  • query l r:查询l到r之间的最小值
  • shift x1 x2 x3:将下标为x1 x2 x3的位置上的数循环移动一个长度。

解题思路:线段树维护最小值,因为每条命令的长度不会超过30,所以循环移动的数并不会很多,用单点修改去处理。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)+1)
const int maxn = 1e5+5;

struct Node {
    int l, r, val;
    Node (int l = 0, int r = 0, int val = 0) {
        this->set(l, r, val);
    }
    void set (int l, int r, int val) {
        this->l = l;
        this->r = r;
        this->val = val;
    }
}node[maxn*4];

int N, M, arr[maxn];

void pushup (int u) {
    int val = min(node[lson(u)].val, node[rson(u)].val);
    node[u].set(node[lson(u)].l, node[rson(u)].r, val);
}

void build_segTree (int u, int l, int r) {

    if (l == r) {
        node[u].set(l, r, arr[l]);
        return;
    }

    int mid = (l + r) / 2;
    build_segTree(lson(u), l, mid);
    build_segTree(rson(u), mid + 1, r);
    pushup(u);
}

void insert_segTree (int u, int pos, int v) {
    if (node[u].l == pos && node[u].r == pos) {
        node[u].val = v;
        return;
    }

    int mid = (node[u].l + node[u].r) / 2;

    if (pos <= mid)
        insert_segTree(lson(u), pos, v);
    else
        insert_segTree(rson(u), pos, v);
    pushup(u);
}

int query_segTree (int u, int l, int r) {
    if (l <= node[u].l && node[u].r <= r)
        return node[u].val;

    int mid = (node[u].l + node[u].r) / 2;

    if (r <= mid)
        return query_segTree(lson(u), l, r);
    else if (l > mid)
        return query_segTree(rson(u), l, r);
    else
        return min(query_segTree(lson(u), l, r), query_segTree(rson(u), l, r));
}

void get_number (int& n, int* num, char* s) {
    n = 0;
    int len = strlen(s), u = 0;

    for (int i = 0; i < len; i++) {
        if (s[i] >= '0' && s[i] <= '9')
            u = u * 10 + s[i] - '0';
        else if (s[i] == ',' || s[i] == ')') {
            num[n++] = u;
            u = 0;
        } else
            u = 0;
    }
}

void solve () {
    int n, num[50];
    char order[50];

    scanf("%s", order);
    get_number(n, num, order);

    if (order[0] == 's') {
        int tmp = arr[num[0]];
        for (int i = 0; i < n - 1; i++) {
            insert_segTree(1, num[i], arr[num[i+1]]);
            arr[num[i]] = arr[num[i+1]];
        }
        insert_segTree(1, num[n-1], tmp);
        arr[num[n-1]] = tmp;
    } else if (order[0] == 'q')
        printf("%d\n", query_segTree(1, num[0], num[1]));
}

int main () {
    while (scanf("%d%d", &N, &M) == 2) {
        for (int i = 1; i <= N; i++)
            scanf("%d", &arr[i]);
        build_segTree(1, 1, N);

        for (int i = 0; i < M; i++)
            solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值