ZCMU—1948

1948: #6029. 「雅礼集训 2017 Day1」市场

Time Limit: 2 Sec  Memory Limit: 256 MB
Submit: 30  Solved: 5
[Submit][Status][Web Board]

Description

从前有一个贸易市场,在一位执政官到来之前都是非常繁荣的,自从他来了之后,发布了一系列奇怪的政令,导致贸易市场的衰落。

有 n nn 个商贩,从 0∼n−1 0 \sim n - 10∼n−1 编号,每个商贩的商品有一个价格 ai a_iai,有两种政令:

  1. l,r,c l, r, cl,r,c,对于 i∈[l,r],ai←ai+c i \in [l, r], a_i \leftarrow a_i + ci∈[l,r],aiai+c
  2. l,r,d l, r, dl,r,d,对于 i∈[l,r],ai←⌊ai/d⌋ i \in [l, r], a_i \leftarrow \lfloor {a_i}/{d} \rfloori∈[l,r],ai←⌊ai/d

现在有一个外乡的旅客想要了解贸易市场的信息,有两种询问方式:

  1. 给定 l,r l, rl,r,求 mini∈[l,r]ai \min_{i \in [l, r]} a_imini∈[l,r]ai
  2. 给定 l,r l, rl,r,求 ∑i∈[l,r]ai \sum_{i\in [l, r]} a_i∑i∈[l,r]ai

Input

第一行为两个空格隔开的整数 n,q n, qn,q 分别表示商贩个数和政令 + 询问个数。
第二行包含 n nn 个由空格隔开的整数 a0∼an−1 a_0 \sim a_{n - 1}a0∼an−1
接下来 q qq 行,每行表示一个操作,第一个数表示操作编号 1∼4 1 \sim 41∼4,接下来的输入和问题描述一致。

Output

对于每个 3、4 操作,输出询问答案。

Sample Input

10 10

-5 -4 -3 -2 -1 0 1 2 3 4

1 0 4 1

1 5 9 1

2 0 9 3

3 0 9

4 0 9

3 0 1

4 2 3

3 4 5

4 6 7

3 8 9

Sample Output

-2

-2

-2

-2

0

1

1

HINT

 

 


对于 30% 30\%30% 的数据,n,q≤103 n, q \leq 10 ^ 3n,q≤103;

对于 60% 60\%60% 的数据,保证数据随机;

对于 100% 100\%100% 的数据,1≤n,q≤105,0≤l≤r≤n−1,c∈[−104,104],d∈[2,109] 1 \leq n, q \leq 10 ^ 5, 0 \leq l \leq r \leq n - 1, c \in [-10 ^ {4}, 10 ^ 4], d \in [2, 10 ^ 9]1≤n,q≤105,0≤lrn−1,c∈[−104,104],d∈[2,109]

 

 

【分析】

区间更新线段树...然后区间查询最小值min和区间和sum,只有一个点需要考虑就是那个区间做除法。

区间做除法所以可以考虑成区间做减法,那么对[l,r]这个区间做除法肯定不能对[l,r]这个区间做一次减法,因为需要减去的数肯定不同,但是可以考虑到一点就是如果某一段需要减去的数字是一样的,那就可以用区间更新的方法更新这一段,从而对整段[l,r]进行更新

所以对于某一段[l,r],判断这一段是否可以减去同一个数字的方法就是看这一段区间的最大值max和最小值min需要减去多少,如果max和min需要减去的数字是一样大的,那么说明这一段都可以减去这个数字,感觉题目中其实给了提示,因为题目中会询问区间最小值,那么既然已经要求最小值了,顺便求个最大值就可以了。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long lnt;
const int N=1E5+5,M=4E5+5;
int s[N],mn[M],mx[M],tg[M];lnt sm[M];
inline void update(int t) {
    int a=t<<1,b=a|1;
    sm[t]=sm[a]+sm[b];
    mn[t]=min(mn[a],mn[b]);
    mx[t]=max(mx[a],mx[b]);
}
void build(int t,int l,int r) {
    if(l==r)sm[t]=mn[t]=mx[t]=s[l];
    else{
        int m=l+r>>1,a=t<<1,b=a|1;
        build(b,m+1,r);
        build(a,l,m);
        update(t);
    }
}
void add(int t,int l,int r,int x,int y,int v) {
    if(l==x&&y==r)sm[t]+=1LL*v*(r-l+1),mx[t]+=v,mn[t]+=v,tg[t]+=v;
    else{
        int m=l+r>>1,a=t<<1,b=a|1;
        if(tg[t])add(a,l,m,l,m,tg[t]),add(b,m+1,r,m+1,r,tg[t]),tg[t]=0;
        if(y<=m)add(a,l,m,x,y,v);
        else if(x>m)add(b,m+1,r,x,y,v);
        else add(a,l,m,x,m,v),add(b,m+1,r,m+1,y,v);
        update(t);
    }
}
int dis(int a,int b) {
    return (a>=0?a/b:(a-b+1)/b)-a;
}
void div(int t,int l,int r,int x,int y,int v) {
    if(l==x&&y==r&&dis(mx[t],v)==dis(mn[t],v))add(t,l,r,x,y,dis(mx[t],v));
    else{
        int m=l+r>>1,a=t<<1,b=a|1;
        if(tg[t])add(a,l,m,l,m,tg[t]),add(b,m+1,r,m+1,r,tg[t]),tg[t]=0;
        if(y<=m)div(a,l,m,x,y,v);
        else if(x>m)div(b,m+1,r,x,y,v);
        else div(a,l,m,x,m,v),div(b,m+1,r,m+1,y,v);
        update(t);
    }
}
lnt sum(int t,int l,int r,int x,int y) {
    if(l==x&&y==r)return sm[t];
    int m=l+r>>1,a=t<<1,b=a|1;
    if(tg[t])add(a,l,m,l,m,tg[t]),add(b,m+1,r,m+1,r,tg[t]),tg[t]=0;
    if(y<=m)return sum(a,l,m,x,y);
    if(x>m)return sum(b,m+1,r,x,y);
    return sum(a,l,m,x,m)+sum(b,m+1,r,m+1,y);
}
int min(int t,int l,int r,int x,int y) {
    if(l==x&&y==r)return mn[t];
    int m=l+r>>1,a=t<<1,b=a|1;
    if(tg[t])add(a,l,m,l,m,tg[t]),add(b,m+1,r,m+1,r,tg[t]),tg[t]=0;
    if(y<=m)return min(a,l,m,x,y);
    if(x>m)return min(b,m+1,r,x,y);
    return min(min(a,l,m,x,m),min(b,m+1,r,m+1,y));
}
int n,m;
signed main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",s+i);
    build(1,1,n);
    for(int i=1,k,x,y,z;i<=m;++i){
        scanf("%d%d%d",&k,&x,&y),++x,++y;
        if(k==4)printf("%lld\n",sum(1,1,n,x,y));
        else if(k==3)printf("%d\n",min(1,1,n,x,y));
        else if(scanf("%d",&z),k==1)add(1,1,n,x,y,z);
        else div(1,1,n,x,y,z);
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值