Gorgeous Sequence

Gorgeous Sequence

时间限制: 3 Sec 内存限制: 128 MB
题目描述
有一个长为n的序列,第i个数为ai。对于这个序列有三种操作方式:
0 x y t:对于任意的x≤i≤y,用min(ai,t)替换原来的ai;
1 x y:输出[x,y]区间所有元素的最大值。
2 x y:输出[x,y]区间所有元素的和。

输入
第一行一个整数T,表示测试点的个数。
对于每个测试点:
第一行两个整数n和m,分别表示序列的长度和操作的次数。
第二行包含n个整数,a1,…,an (∀1≤i≤n,0≤ai<231)。
接下来m行,每行代表一次操作,其中(1≤x≤y≤n,0≤t<231)。
所有数据保证T=100, ∑n≤1000000, ∑m≤1000000。

输出
对于每个操作1或2,请输出相应查询的答案。

样例输入
1
5 5
1 2 3 4 5
1 1 5
2 1 5
0 3 5 3
1 1 5
2 1 5

样例输出
5
15
3
12

来源
hdu2015多校

题解

对于每次修改操作,在找到一个区间后将标记尽可能下传,直到一个区间内不会增加被修改的数字时才结束。
考虑复杂度,每个数字最多只会被标记一次,每次需要logn次操作。所以效率为nlogn。(瞎证明的,欢迎更科学的证明)

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define N 1000010
#define ll long long
using namespace std;
int Q,n,m,s[N];
struct node{int maxn,num,lazy;ll sum;}t[N*4];

inline int get()
{
  char ch;
  while(!isdigit(ch=getchar()));
  int v=ch-48;
  while(isdigit(ch=getchar()))v=v*10+ch-48;
  return v;
}

class seg_tree
{
  inline void update(int x)
  {
    int lc=x<<1,rc=lc+1;
    t[x].maxn=max(t[lc].maxn,t[rc].maxn);
    t[x].sum=t[lc].sum+t[rc].sum;
    t[x].num=t[lc].num+t[rc].num;
  }
  void work(int x,int l,int r,int num)
  {
    if(t[x].lazy<=num&&t[x].lazy)return;
    t[x].lazy=num;t[x].sum+=(ll)(r-l+1-t[x].num)*num;
    if(t[x].num<r-l+1)t[x].maxn=num,t[x].num=r-l+1;
  }
  inline void pushdown(int x,int l,int r)
  {
    if(!t[x].lazy)return;
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    work(lc,l,mid,t[x].lazy);
    work(rc,mid+1,r,t[x].lazy);
    t[x].lazy=0;
  }
  public:
  inline void build(int x,int l,int r)
  {
    t[x].lazy=0;
    if(l==r)
    {
      t[x].maxn=s[l];t[x].lazy=s[l];
      t[x].sum=s[l];t[x].num=1;return;
    }
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    build(lc,l,mid);build(rc,mid+1,r);
    update(x);
  }
  inline void find(int x,int l,int r,int num)
  {
    if(t[x].maxn<=num)return;
    if(t[x].lazy>num)t[x].lazy=0;
    if(l==r)
    {
      t[x].maxn=t[x].lazy;t[x].sum=t[x].lazy;
      t[x].num=t[x].lazy?1:0;return;
    }
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    pushdown(x,l,r);
    find(lc,l,mid,num);
    find(rc,mid+1,r,num);
    update(x);
  }
  inline void modify(int x,int l,int r,int ql,int qr,int num)
  {
    if(t[x].maxn<=num)return;
    if(ql<=l&&r<=qr){find(x,l,r,num);work(x,l,r,num);return;}
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    pushdown(x,l,r);
    if(ql<=mid)modify(lc,l,mid,ql,qr,num);
    if(qr>mid)modify(rc,mid+1,r,ql,qr,num);
    update(x);
  }
  inline int qry1(int x,int l,int r,int ql,int qr)
  {
    if(ql<=l&&r<=qr)return t[x].maxn;
    int mid=l+r>>1,lc=x<<1,rc=lc+1,res=0;
    pushdown(x,l,r);
    if(ql<=mid)res=max(res,qry1(lc,l,mid,ql,qr));
    if(qr>mid)res=max(res,qry1(rc,mid+1,r,ql,qr));
    return res;
  }
  inline ll qry2(int x,int l,int r,int ql,int qr)
  {
    if(ql<=l&&r<=qr)return t[x].sum;
    int mid=l+r>>1,lc=x<<1,rc=lc+1;ll res=0;
    pushdown(x,l,r);
    if(ql<=mid)res+=qry2(lc,l,mid,ql,qr);
    if(qr>mid)res+=qry2(rc,mid+1,r,ql,qr);
    return res;
  }
}T;

int main()
{
  int type,a,b,c;
  Q=get();
  while(Q--)
  {
    n=get();m=get();
    for(int i=1;i<=n;i++)s[i]=get();
    T.build(1,1,n);
    for(int i=1;i<=m;i++)
    {
      type=get();a=get();b=get();
      if(!type)c=get(),T.modify(1,1,n,a,b,c);
      if(type==1)printf("%d\n",T.qry1(1,1,n,a,b));
      if(type==2)printf("%lld\n",T.qry2(1,1,n,a,b));
    }
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值