CF52C Circular RMQ

题目地址
题目描述
You are given circular array a_{0},a_{1},…,a_{n-1}a
0

,a
1

,…,a
n−1

. There are two types of operations with it:

inc(lf,rg,v)inc(lf,rg,v) — this operation increases each element on the segment [lf,rg][lf,rg] (inclusively) by vv ;
rmq(lf,rg)rmq(lf,rg) — this operation returns minimal value on the segment [lf,rg][lf,rg] (inclusively).
Assume segments to be circular, so if n=5n=5 and lf=3,rg=1lf=3,rg=1 , it means the index sequence: 3,4,0,13,4,0,1 .

Write program to process given sequence of operations.

输入格式
The first line contains integer nn ( 1<=n<=2000001<=n<=200000 ). The next line contains initial state of the array: a_{0},a_{1},…,a_{n-1}a
0

,a
1

,…,a
n−1

( -10{6}<=a_{i}<=10{6}−10
6
<=a
i

<=10
6
), a_{i}a
i

are integer. The third line contains integer mm ( 0<=m<=2000000<=m<=200000 ), mm — the number of operartons. Next mm lines contain one operation each. If line contains two integer lf,rglf,rg ( 0<=lf,rg<=n-10<=lf,rg<=n−1 ) it means rmqrmq operation, it contains three integers lf,rg,vlf,rg,v ( 0<=lf,rg<=n-1;-10{6}<=v<=10{6}0<=lf,rg<=n−1;−10
6
<=v<=10
6
) — incinc operation.

输出格式
For each rmqrmq operation write result for it. Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preffered to use cout (also you may use %I64d).

题意翻译
【题目大意】

给定一个环形数列 a_0,a_1,\dots,a_{n-1}a
0

,a
1

,…,a
n−1

现在有 22 种操作:

\operatorname{inc}(lf,rg,v)inc(lf,rg,v):将区间 [lf,rg][lf,rg] 中的每个数增加 vv。
\operatorname{rmq}(lf,rg)rmq(lf,rg):求出区间 [lf,rg][lf,rg] 中的最小值。
因为数列是环形的,所以当 n=5n=5,lf=3lf=3,rg=1rg=1 时,表示的区间下标为 3,4,0,13,4,0,1。

Translated by 小恐。

【输入】

第一行有一个整数 nn。

第二行为数列的初始状态 a_0,a_1,\dots,a_{n-1}a
0

,a
1

,…,a
n−1

,a_ia
i

是整数。

第三行有一个整数 mm,表示操作次数。

接下来m行每行为一个操作。如果该行有两个整数 lflf,rgrg 表示 \operatorname{rmq}rmq 操作,如果该行有三个整数 lflf,rgrg,vv 表示 \operatorname{inc}inc 操作。

【输出】

对于每个 \operatorname{rmq}rmq 操作输出一行答案。

求区间最小值,这道题加深了我对线段树的理解。
同时每一行可以用快速读入判断空格个数来判断输入个数。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const long long inf=0x3f3f3f3f;
int a[200010],space;
struct node{
    int l,r,len,lazy,val,mi;
}tree[800010];//树状数组的大小要是数据量的4倍
int read(){
	int res=0,f=1;
	char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
	while (isdigit(c)) res=res*10+c-48,c=getchar();
	if (c==' ') ++space; //空格的个数
	return res*f;
}
void buil(int l,int r,int root){//构造线段树
    tree[root].l=l;
    tree[root].r=r;
    tree[root].lazy=0;
    tree[root].len=r-l+1;//根据需要可添加其它元素
    tree[root].mi=inf;
    if(l==r){
        tree[root].val=a[l];
        tree[root].mi=a[l];
    }
    else{
        int m=(l+r)/2;
        buil(l,m,root*2);
        buil(m+1,r,root*2+1);
        tree[root].val=tree[root*2].val+tree[root*2+1].val;
        tree[root].mi=min(tree[root*2].mi,tree[root*2+1].mi);
    }
}

void pushdown(int root){//下推
    if(tree[root].lazy){
        tree[root*2].lazy+=tree[root].lazy;
        tree[root*2+1].lazy+=tree[root].lazy;
        tree[root*2].val+=tree[root].lazy*tree[root*2].len;      //根据需要变更,
        tree[root*2+1].val+=tree[root].lazy*tree[root*2+1].len;  //是累加+=还是赋值=
        tree[root*2].mi+=tree[root].lazy;
        tree[root*2+1].mi+=tree[root].lazy;
        tree[root].lazy=0;
    }
}

void updata(int l,int r,int root,int x){//区间更新
    if(l<=tree[root].l&&tree[root].r<=r){
        tree[root].val+=x*tree[root].len;//根据需要变更,是累加+=还是赋值=
        tree[root].lazy+=x;
        tree[root].mi+=x;
        return;
    }
    if(r<tree[root].l||tree[root].r<l) return;
    pushdown(root);
    updata(l,r,root*2,x);
    updata(l,r,root*2+1,x);
    tree[root].val=tree[root*2].val+tree[root*2+1].val;
    tree[root].mi=min(tree[root*2].mi,tree[root*2+1].mi);
}

int query(int l,int r,int root){//区间查询,注意返回类型
    if(l<=tree[root].l&&tree[root].r<=r)return tree[root].mi;
    if(r<tree[root].l||tree[root].r<l)return inf;//如果用min则return inf
    pushdown(root);
    return min(query(l,r,root*2),query(l,r,root*2+1));
}



signed main(){

    ios::sync_with_stdio(0);
    int T,n,m,x;
    n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    m=read();

    buil(1,n,1);
        //for(int i=1;i<=4*n;i++)cout<<tree[i].mi<<' ';cout<<endl;
    while(m--){
        int l,r,x;
        space=0;
        l=read();r=read();
        l++,r++;
        if(space==2){
            x=read();
            if(r>=l)updata(l,r,1,x);
            else {
                updata(l,n,1,x);
                updata(1,r,1,x);
            }
            //for(int i=1;i<=4*n;i++)cout<<tree[i].mi<<' ';cout<<endl;
        }
        else{
           if(r>=l)cout<<query(l,r,1)<<endl;
           else {
                cout<<min(query(l,n,1),query(1,r,1))<<endl;
            }
        }

    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值