线段树--点修改(uva12299)

题目链接:(https://vjudge.net/problem/UVA-12299)
分析:
两种操作,查询[x,y]之间的最小值,第二种是把给定位置的元素循环左移,若是最前面的,则移到最后面。将给定位置的节点值记录一下,再循环左移就行。注意建树的过程是n*logn的时间复杂度。另外注意输入的处理,%6s代表输入6个字符。这次真是吃了血亏,在每个操作输入之间要加getchar()吃掉回车,我没加,因为我的电脑运行没毛病,结果wrong成狗,记得要吃掉回车
代码如下:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=100000+5;
int minv[maxn<<2];
vector<int>value_v;   //记录给定位置的值
vector<int>p;          //保存给定位置
//获得给定位置p的元素的编号
int Get_ID(int p,int l,int r,int rt)
{
    if(l==r)return rt;
    int m=(l+r)>>1;
    if(p<=m)Get_ID(p,l,m,rt<<1);
    else Get_ID(p,m+1,r,rt<<1|1);
}
//建树
void build(int l,int r,int rt)
{
    if(l==r)
    {
        scanf("%d",&minv[rt]);  //建树的过程中输入
        return ;
    }
    int m=(l+r)>>1;       //x>>1==x/2
    build(l,m,rt<<1);       //向左走 x<<1==x*2
    build(m+1,r,rt<<1|1);  //向右走,(x<<1|1)==x*2+1
    minv[rt]=min(minv[rt<<1],minv[rt<<1|1]);
}
//更新,将p位置的值改为c
void update(int p,int c,int l,int r,int rt)
{
    if(l==r)
    {
        minv[rt]=c;
        return ;
    }
    int m=(l+r)>>1;
    if(p<=m)update(p,c,l,m,rt<<1);
    if(p>m)update(p,c,m+1,r,rt<<1|1);
    minv[rt]=min(minv[rt<<1],minv[rt<<1|1]);
}
//查询,返回区间最小值
int query(int ll,int rr,int l,int r,int rt)
{
    if(ll<=l&&rr>=r)
        return minv[rt];
    int m=(l+r)>>1;
    int cnt=INF;
    if(ll<=m)
        cnt=min(cnt,query(ll,rr,l,m,rt<<1));
    if(rr>m)
        cnt=min(cnt,query(ll,rr,m+1,r,rt<<1|1));
    return cnt;
}
int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    build(1,n,1);
    char op[50];
    while(q--)
    {
        getchar();
        scanf("%6s",op);
        if(op[0]=='q')
        {
            int x,y;
            scanf("%d,%d%)",&x,&y);
            printf("%d\n",query(x,y,1,n,1));
        }
        else if(op[0]=='s')
        {
            p.clear();
            char c;
            int x;
            while(scanf("%d%c",&x,&c))
            {
                p.push_back(x);
                if(c!=',')
                    break;
            }

            for(int i=0; i<p.size(); i++)
            {
                int id=Get_ID(p[i],1,n,1); //找到给定位置元素的编号
                value_v.push_back(minv[id]);
            }
            //循环左移
            for(int i=0; i<p.size(); i++)
            {
                update(p[i],value_v[(i+1)%p.size()],1,n,1);
            }
            value_v.clear();  //注意清空,防止影响下一次操作
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值