首页 > 其他分享 >UVA12299 RMQ with Shifts

UVA12299 RMQ with Shifts

时间:2023-01-16 19:34:30浏览次数:35  
标签:RMQ leq int 30 修改 Shifts query 操作 UVA12299

简要题意

你需要维护一个长为 \(n\) 的序列 \(a\),支持以下操作:

  • shift(i1,i2,...,ik) 对于 \(1 \leq p \leq k\),将 \(a_{i_p}\) 赋值为 \(a_{i_{(p \bmod k) + 1}}\)。
  • query(l,r) 查询区间 \([l,r]\) 的最小值。

\(1 \leq n \leq 10^5,1 \leq q \leq 2.5\times 10^5\),输入的操作长度不超过 \(30\)。

思路

输入操作长度不超过 \(30\) 这个条件很关键。它告诉我们,最多有 \(30\) 个元素会被修改,而 \(30\) 很小,完全可以逐个单点修改来实现。具体做法是,储存一下 \(v=a_{i_1}\),然后逐个按题面修改,最后将 \(a_{i_k}\) 修改为 \(v\) 即可。

于是这道题可以用一个支持单点修改,区间最小值的数据结构解决,恰好,线段树就可以胜任这两个操作。

时间复杂度 \(O(n+q\log n)\),完全可以通过本题。

最后讲一讲输入,貌似题解里没有我这么输入的。

我的输入方法是:每个操作用 std::cin 读入一个字符串,然后从第 \(6\) 个字符(下标从 \(0\) 开始,这样子会跳过前面的引导字符串和一个左括号)。然后每遇到一个字符,进行分类讨论:

  • 如果是右括号,直接忽略。
  • 如果是逗号,则将计数器加 \(1\),下一次存储时会存储到右边的位置中。
  • 如果是数字,将计数器所对应的数据乘上 \(10\) 加上这个字符表示的数字。

然后查询操作就是前两个数据,修改操作就是读进来的全部数据。

这个写法个人觉得比其他写法更简便、好懂,也不易写错。

代码

#include <bits/stdc++.h>
#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
using namespace std;

int n,q;
const int N = 100005;
int mint[N<<2];

void pushup(int i){
    mint[i]=min(mint[ls],mint[rs]);
}

void build(int i,int l,int r){
    if(l==r){
        cin>>mint[i];
        return;
    }
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(i);
}

void update(int p,int v,int i,int l,int r){
    if(l==r){
        mint[i]=v;return;
    }
    if(p<=mid) update(p,v,ls,l,mid);
    else update(p,v,rs,mid+1,r);
    pushup(i);
}

int query(int ql,int qr,int i,int l,int r){
    if(ql<=l&&r<=qr) return mint[i];
    int ans=INT_MAX;
    if(ql<=mid) ans=min(ans, query(ql,qr,ls,l,mid));
    if(qr>mid) ans=min(ans, query(ql,qr,rs,mid+1,r));
    return ans;
}

void shift(int *ids,int size){
    int first = query(ids[0], ids[0], 1, 1, n);
    for(int i=0;i<size-1;i++){
        update(ids[i], query(ids[i+1], ids[i+1], 1, 1, n), 1, 1, n);
    }
    update(ids[size-1], first, 1, 1, n);
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>q;
    build(1,1,n);
    while(q--){
        string str;
        cin>>str;
        int arr[30],tot=0;
        memset(arr,0,sizeof(arr));
        for(int i=6;i<str.size();i++){
            if(str[i] == ')') continue;
            if(str[i] == ',') tot++;
            else arr[tot]=arr[tot]*10+(str[i]-'0');
        }
        if(str[0] == 'q') cout<<query(arr[0], arr[1], 1,1, n)<<'\n';
        else {
            shift(arr, tot+1);
        }
    }
    return 0;
}

标签:RMQ,leq,int,30,修改,Shifts,query,操作,UVA12299
From: https://www.cnblogs.com/zheyuanxie/p/uva12299.html

相关文章

  • [RMQ记录] P2048 [NOI2010] 超级钢琴
    题目如果枚举所有的情况肯定是不行的。不过可以发现一些对答案完全没有影响的答案也被枚举,十分浪费时间,所以下面介绍一种很好的思路。首先,考虑优化暴力(暴力指用堆维护每......
  • python之路52 ORMQ查询、ORM事务、查询优化、常用字段及参数、ajax方法
    Q查询进阶操作fromdjango.db.modelsimportQq_obj=Q()#1.产生q对象q_obj.connector='or'#默认多个条件的连接是and可以修改为orq_obj.children.append(('......
  • hdu3078 Network--RMQ & LCA
    原题链接:​​http://acm.hdu.edu.cn/showproblem.php?pid=3078​​题意:给定n个点标号1到n,每个点一个权值,接下来n-1行u,v表示u和v两点连线,接下来k行查询,op,u,v,如果u为0,表示把点u......
  • LCA 和 RMQ 互化
    简单记录一下。RMQ转LCA:建立笛卡尔树即可。为啥:考虑树上的点\(lca(u,v)\),其必为\([u,v]\)中的点。对于所有以其为根的子树中的点,一定比其权值小/大,不在子树中的点,不......
  • docker部署RockerMQ单机测试环境
    1.RocketMQ创建专属网络[root@mq011~]#dockernetworkcreaterocketmq154dc65dce84ce5d417e9e2787bdd77de881ac65575e5e74fed4aeaf99830984[root@mq011~]#docker......
  • [拆位线段树]RMQ
    [拆位线段树]RMQ题目​​https://ac.nowcoder.com/acm/problem/21414​​思路区间或,区间求和对于区间或,异或这种位运算,没法之间打懒标记。但是如果我们按位拆分,可以发现对......
  • CF803G Periodic RMQ Problem
    这题很妙,当时用CD的方法,写平衡树,但是吧没有领会精神,写了200多行,发现前驱后继又不合法的情况,好像要写12种情况,就不想写了。然后就突然明白线段树做法了。。。介绍一种线段......
  • ST表&倍增&RMQ问题
    ST表,SparseTable,是解决区间最值问题,及RMQ问题的工具,利用倍增思想,O(N*log2(N))预处理,O(1)查询。设f[i][j]表示从i开始的2^j个数的最值,初始化f[i][0]=a[i],对于处理f数组,......
  • rmq板子
    typedeflonglongLL;constexprinlineintlg2(LLx){returnsizeof(LL)*8-1-__builtin_clzll(x);}template<typenameT,size_tN,size_tK>structRangeQ......
  • G. Periodic RMQ Problem
    G.PeriodicRMQProblem题目大意给你一个序列\(a\)让你支持\(1\)\(l\)\(r\)\(x\)区间赋值\(2\)\(l\)\(r\)询问区间最小值我们觉得这个问题太水了,所以我们......