NBUT - 1113【线段树单点修改】

In the traditional RMQ (Range Minimum Query) problem, we have a static array A. Then for each query (L, R) (L<=R), we report the minimum value among A[L], A[L+1], …, A[R]. Note that the indices start from 1, i.e. the left-most element is A[1].

In this problem, the array A is no longer static: we need to support another operation shift(i1, i2, i3, …, ik) (i1<i2<...<ik,k>1): ( i 1 < i 2 < . . . < i k , k > 1 ) : we do a left “circular shift” of A[i1], A[i2], …, A[ik].
For example, if A={6, 2, 4, 8, 5, 1, 4}, then shift(2, 4, 5, 7) yields {6, 8, 4, 5, 4, 1, 2}. After that, shift(1,2) yields{8, 6, 4, 5, 4, 1, 2}.
在传统的RMQ(Range Minimum Query)问题中,我们有一个静态数组A.然后对于每个查询(L,R)(L <= R),我们报告A [L],A [L + 1 ],…,A [R]。 请注意,索引从1开始,即最左边的元素是A [1]。

在这个问题中,数组A不再是静态的:我们需要支持另一个操作移位 i1i2i3...iki1<i2<...<ikk>1 ( i 1 , i 2 , i 3 , . . . , i k ) ( i 1 < i 2 < . . . < i k , k > 1 ) :我们做一个左移 A [i1],A [i2],…,A [ik]的“循环移位”。

例如,如果A = {6,2,4,8,5,1,4},则移位(2,4,5,7)产生{6,8,4,5,4,1,2}。 之后,移位(1,2)产生{8,6,4,5,4,1,2}。

Input
There will be only one test case, beginning with two integers n, q (1<=n<=100,000, 1<=q<=120,000), the number of integers in array A, and the number of operations. The next line contains n positive integers not greater than 100,000, the initial elements in array A. Each of the next q lines contains an operation. Each operation is formatted as a string having no more than 30 characters, with no space characters inside. All operations are guaranteed to be valid. Warning: The dataset is large, better to use faster I/O methods.
将只有一个测试用例,以两个整数n,q(1 <= n <= 100,000,1 <= q <= 120,000),数组A中的整数数量以及操作次数开始。 下一行包含n个不大于100,000的正整数,即数组A中的初始元素。下一个q行中的每一行都包含一个操作。 每个操作都被格式化为不超过30个字符的字符串,里面没有空格字符。 所有操作都保证有效。 警告:数据集很大,最好使用更快的I / O方法。

Output
For each query, print the minimum value (rather than index) in the requested range.
对于每个查询,在要求的范围内输出最小值(而不是索引)。

Sample Input
7 5
6 2 4 8 5 1 4
query(3,7)
shift(2,4,5,7)
query(1,4)
shift(1,2)
query(2,2)
Sample Output
1
4
6

思路:单点修改,区间查询最小值,线段树裸题。要注意的是注意处理输入字符串,修改值时保存存最后一个值,最后修改‘

#include <cstdio> 
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

typedef long long LL;
const int MAXN = 2e5 + 10;
char str[1010];
int dp[MAXN << 2], a[MAXN << 1];
int ans;

inline void pushup(int root) {
    dp[root] = min(dp[root << 1], dp[root << 1 | 1]);
}

inline void build(int root, int L, int R) {
    if(L == R) {
        scanf("%d", &a[L]);
        dp[root] = a[L];
        return ;
    }
    int mid = (L + R) >> 1;
    build(root << 1, L, mid);
    build(root << 1 | 1, mid + 1, R);
    pushup(root);
}

inline void updata(int root, int L, int R, int x, int y) {
    if(L == R) {
        dp[root] = a[y];
        a[x] = a[y];
        return ;
    }
    int mid = (L + R) >> 1;
    if(x <= mid) updata(root << 1, L, mid, x, y);
    else updata(root << 1 | 1, mid + 1, R, x, y);
    pushup(root);
}

inline void updata_cnt(int root, int L, int R, int x, int y) {
    if(L == R) {
        dp[root] = y;
        a[x] = y;
        return ;
    }
    int mid = (L + R) >> 1;
    if(x <= mid) updata_cnt(root << 1, L, mid, x, y);
    else updata_cnt(root << 1 | 1, mid + 1, R, x, y);
    pushup(root);
}

inline void query(int root, int L, int R, int l, int r) {
    if(L >= l && R <= r) {
        ans = min(ans, dp[root]);
        return;
    }
    int mid = (L + R) >> 1;
    if(mid >= l) query(root << 1, L, mid, l, r);
    if(r > mid) query(root << 1 | 1, mid + 1, R, l, r);
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    build(1, 1, n);
    while(m--) {
        scanf("%s", str);
        int len = strlen(str);
        int b[110], p = 0, res = 0;
        for(int i = 6; i < len; ++i) { //注意处理字符串,数位比较多
            if(str[i] >= '0' && str[i] <= '9') {
                res = res * 10 + str[i] - '0';
            }
            else if(str[i] != ')') {
                b[p++] = res;
                res = 0;
            }
            else break;
        }
        b[p++] = res;
        if(str[0] == 'q') {
            ans = 0x3f3f3f3f;
            query(1, 1, n, b[0], b[1]);
            printf("%d\n", ans);
        }
        else {
            int cnt = a[b[0]]; 
            for(int i = 0; i < p - 1; i++) {
                updata(1, 1, n, b[i], b[i + 1]);
            }
            updata_cnt(1, 1, n, b[p - 1], cnt); //修改最后一个值
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值