UVA 12299 - RMQ with Shifts(线段树单点更新+模拟)

题目链接 https://cn.vjudge.net/problem/UVA-12299

【题意】
对于一个给定的数组A[1],A[2]…A[n],支持以下两种操作
query(L,R) 查询区间[L,R]中的最小元素值
shift (i1,i2,..ik) 把元素A[i1],A[i2]…A[ik]的元素循环左移一位
如A={6,2,4,8,5,1,4},执行shift(2,4,5,7)后,A={6,8,4,5,4,1,2}

【输入格式】
单组输入,第一行是两个整数n,q(1<=n<=100000,1<=q<=250000)代表数组的元素个数和操作次数,然后是n个不超过100000的正整数,代表A的初值.以下q行每行一个合法的字符串表示一个操作,长度不超过30,不含空白字符.

【输出格式】
对每组query操作,输出查询结果即对应区间的最小值

【思路】
可以对A构造一颗线段树,维护区间的最小值,然后解析输入的字符串,得到需要查询或修改的下标.对query操作直接查询输出即可,对shift操作,记录下第一个下标对应的元素值,然后把后面的所有元素都向前推一位,同时更新线段树,最后用第一个元素值更新最后一个下标对应的元素值.

#include<bits/stdc++.h>
using namespace std;
#define node tree[id]
#define lson tree[id<<1]
#define rson tree[id<<1|1]

const int inf=2e9;
const int maxn=100050;

struct Tree{
    int left,right;
    int minv;
};

int n,q;
int a[maxn];
Tree tree[maxn<<2];
char op[100];

void pushup(int id){ node.minv=min(lson.minv,rson.minv); }

void build(int id,int le,int ri){
    node.left=le;
    node.right=ri;
    if(le==ri){
        node.minv=a[le];
        return;
    }
    int mid=(le+ri)>>1;
    build(id<<1,le,mid);
    build(id<<1|1,mid+1,ri);
    pushup(id);
}

int query(int id,int x,int y){
    if(node.left==x && node.right==y){
        return node.minv;
    }
    int mid=(node.left+node.right)>>1;
    if(x>mid) return query(id<<1|1,x,y);
    else if(y<=mid) return query(id<<1,x,y);
    else{
        int ans=inf;
        ans=min(ans,query(id<<1,x,mid));
        ans=min(ans,query(id<<1|1,mid+1,y));
        return ans;
    }
}

void update(int id,int pos,int v){
    if(node.left==node.right){
        node.minv=v;
        return;
    }
    int mid=(node.left+node.right)>>1;
    if(pos<=mid) update(id<<1,pos,v);
    else update(id<<1|1,pos,v);
    pushup(id);
}

int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    build(1,1,n);
    while(q--){
        memset(op,0,sizeof(op));
        scanf("%s",op);
        vector<int> v;
        for(int i=0;op[i];){
            if(!isdigit(op[i])) ++i;
            else{
                v.push_back(atoi(op+i));
                int j=i+1;
                while(isdigit(op[j])) ++j;
                i=j;
            }
        }
        //for(int i=0;i<v.size();++i) cout<<v[i]<<" ";
        //cout<<endl;
        if(op[0]=='q'){
            int ans=query(1,v[0],v[1]);
            printf("%d\n",ans);
        }
        else{
            int tmp=a[v[0]];
            for(int i=0;i<v.size()-1;++i){
                a[v[i]]=a[v[i+1]];
                update(1,v[i],a[v[i]]);
            }
            a[v[v.size()-1]]=tmp;
            update(1,v[v.size()-1],tmp);
        }
    }
    return 0;
}
阅读更多
文章标签: 线段树
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭