ZCUM-1948: #6029. 「雅礼集训 2017 Day1」市场 线段树区间更新

题目连接:点击打开链接

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

有 n nn 个商贩,从 0∼n−1 0 \sim n - 10n1 编号,每个商贩的商品有一个价格 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],aiai/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_ii[l,r]ai

Input

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

Output

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

线段树的操作,有一点这题除法的时候是向下取整,当时没看见,卡了很久。

不知道为什么这种线段树总感觉怪怪的,不能真正诠释线段树这个东西,感觉在数据比较极端的情况下会超时。

哎,可能是因为我太菜了,没能理解。。。

首先这里有一个向下取整的操作,就很烦。那么我们把除法变成减法的操作就简单了,但必须是区间内所有的数减的是一样的。

那咋办,,判断最大的数需要减多少盒最小的数需要减多少,如果一样的话就用区间更新的操作,如果不一样那就继续搜。。

还有一点就是负数和非负数要分情况讨论,其他也就没什么了。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100010;
const ll inf=1e18;
ll sum[maxn<<2],lazy[maxn<<2];
ll d[maxn<<2],x[maxn<<2];
void up(int root)
{
    sum[root]=sum[root<<1]+sum[root<<1|1];
    d[root]=max(d[root<<1],d[root<<1|1]);
    x[root]=min(x[root<<1],x[root<<1|1]);
    return;
}
void down(int root,int l,int r)
{
    lazy[root<<1]+=lazy[root];
    lazy[root<<1|1]+=lazy[root];
    int mid=(l+r)/2;
    sum[root<<1]+=(mid-l+1)*lazy[root];
    sum[root<<1|1]+=(r-mid)*lazy[root];
    x[root<<1]+=lazy[root];
    x[root<<1|1]+=lazy[root];
    d[root<<1]+=lazy[root];
    d[root<<1|1]+=lazy[root];
    lazy[root]=0;
}
void build(int root,int l,int r)
{
    lazy[root]=0;
    if(l==r)
    {
        scanf("%lld",&sum[root]);
        d[root]=x[root]=sum[root];
        return;
    }
    int mid=(l+r)/2;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    up(root);
}
void updata1(int root,int nowa,int nowb,int l,int r,int val)
{
    if(nowb<l||r<nowa) return;
    if(l<=nowa&&nowb<=r)
    {
        sum[root]+=(nowb-nowa+1)*val;
        d[root]+=val;
        x[root]+=val;
        lazy[root]+=val;
        return;
    }
    if(lazy[root]) down(root,nowa,nowb);
    int mid=(nowa+nowb)/2;
    updata1(root<<1,nowa,mid,l,r,val);
    updata1(root<<1|1,mid+1,nowb,l,r,val);
    up(root);
}
void updata2(int root,int nowa,int nowb,int l,int r,int val)
{
    if(nowb<l||r<nowa) return;
    if(l<=nowa&&nowb<=r)
    {
        ll X,Y;
        if (x[root]>=0) X=x[root]/val;
        else X=(x[root]-val+1)/val;
        if (d[root]>=0) Y=d[root]/val;
        else Y=(d[root]-val+1)/val;
        if (X-x[root]==Y-d[root])
        {
            lazy[root]+=X-x[root];
            sum[root]+=(X-x[root])*(nowb-nowa+1);
            d[root]+=X-x[root];
            x[root]+=X-x[root];
            return ;
        }
    }
    if(lazy[root]) down(root,nowa,nowb);
    int mid=(nowa+nowb)/2;
    updata2(root<<1,nowa,mid,l,r,val);
    updata2(root<<1|1,mid+1,nowb,l,r,val);
    up(root);
}
ll query1(int root,int nowa,int nowb,int l,int r)
{
    if(nowb<l||r<nowa) return 0;
    if(l<=nowa&&nowb<=r) return sum[root];
    if(lazy[root]) down(root,nowa,nowb);
    int mid=(nowa+nowb)/2;
    ll ans=0;
    ans+=query1(root<<1,nowa,mid,l,r);
    ans+=query1(root<<1|1,mid+1,nowb,l,r);
    up(root);
    return ans;
}
ll query2(int root,int nowa,int nowb,int l,int r)
{
    if(nowb<l||r<nowa) return inf;
    if(l<=nowa&&nowb<=r) return x[root];
    if(lazy[root]) down(root,nowa,nowb);
    int mid=(nowa+nowb)/2;
    ll ans=inf;
    ans=min(ans,query2(root<<1,nowa,mid,l,r));
    ans=min(ans,query2(root<<1|1,mid+1,nowb,l,r));
    up(root);
    return ans;
}
int main()
{
    int n,q,op,x,y,z;
    scanf("%d%d",&n,&q);
    build(1,0,n-1);
    while(q--)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d%d",&x,&y,&z);
            updata1(1,0,n-1,x,y,z);
        }
        else if(op==2)
        {
            scanf("%d%d%d",&x,&y,&z);
            updata2(1,0,n-1,x,y,z);
        }
        else if(op==3)
        {
            scanf("%d%d",&x,&y);
            printf("%lld\n",query2(1,0,n-1,x,y));
        }
        else
        {
            scanf("%d%d",&x,&y);
            printf("%lld\n",query1(1,0,n-1,x,y));
        }
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_41713256/article/details/80482763