BZOJ 4695

4695: 最假女选手

Time Limit: 50 Sec   Memory Limit: 128 MB
Submit: 126   Solved: 23
[ Submit][ Status][ Discuss]

Description

在刚刚结束的水题嘉年华的压轴节目放水大赛中,wyywyy如愿以偿的得到了最假女选手的奖项。但是作为主办人的
C_SUNSHINE为了证明wyywyy确实在放水,决定出一道基础题考察wyywyy的姿势水平。给定一个长度为 N序列,编号
从1 到 N。要求支持下面几种操作:
1.给一个区间[L,R] 加上一个数x 
2.把一个区间[L,R] 里小于x 的数变成x 
3.把一个区间[L,R] 里大于x 的数变成x 
4.求区间[L,R] 的和
5.求区间[L,R] 的最大值
6.求区间[L,R] 的最小值

Input

第一行一个整数 N表示序列长度。
第二行N 个整数Ai 表示初始序列。
第三行一个整数M 表示操作个数。
接下来M 行,每行三或四个整数,第一个整数Tp 表示操作类型,接下来L,R,X 或L,R 表述操作数。
1<=tp<=6,N,M<=5*10^5,|Ai|<=10^8
Tp=1时,|x|<=1000
Tp=2或3时,|x|<=10^8

Output

对于每个4,5,6类型的操作输出一行一个整数表示答案。

Sample Input

2
1 2
2
2 1 2 2
4 1 2

Sample Output

4

1操作好搞

2操作就维护一个次大值,一个最大值和最大值出现次数(复杂度证明在传送门)

  在x>=最大值时return

  在x<次大值时继续递归modify

  在次大值<=x<最大值时打上标记

  更新时很恶心,先要更新sum,然后要用x去更新最大值,最小值和次小值

  如果最小值==最大值,说明这个区间内数已经相同了,就需要再次修改次大次小值

  要把3操作的标记更新.

其他操作就随意脑补一下好了

PS:我好像写丑了...加了读入优化,BZOJ续了1s才过...

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define inf (1<<30)
#define maxn 500005
using namespace std;
typedef long long ll;
struct segtree{
    ll add,sum;
    int mntox,mxtox,mxs,mns,mx1,mx2,mn1,mn2,l,r;
    void clear(){mx1=mx2=-inf;mn1=mn2=inf;sum=add=mxs=mns=0;mntox=-inf,mxtox=inf;}
}s[maxn<<2];
int a[maxn],n,m;
int inline read(){
    register char act=0;
    register int f=1,x=0;
    while(act=getchar(),act<'0'&&act!='-');
    if(act=='-')f=-1,act=getchar();
    x=act-'0';
    while(act=getchar(),act>='0')x=x*10+act-'0';
    return x*f;
}
 
bool updmax(int o,int mxtox){
    if(s[o].mx1<=mxtox)return 0;
    if(s[o].mx2<mxtox){
//      printf("max{%d,%d,(%d,%d)}",s[o].mxs,s[o].mx1,s[o].l,s[o].r);
        s[o].sum=s[o].sum-(ll)s[o].mxs*s[o].mx1+(ll)s[o].mxs*mxtox;
        s[o].mn1=min(s[o].mn1,s[o].mx1=mxtox);
        s[o].mn2=min(s[o].mn2,mxtox);
        if(s[o].mn1==mxtox)s[o].mn2=inf,s[o].mx2=-inf,s[o].mxs=s[o].mns=s[o].r-s[o].l+1;
        s[o].mntox=min(s[o].mxtox=min(s[o].mxtox,mxtox),s[o].mntox);
        return 0;
    }
    return 1;
}
bool updmin(int o,int mntox){
    if(s[o].mn1>=mntox)return 0;
    if(s[o].mn2>mntox){
//      printf("min{%d,%d,(%d,%d)}",s[o].mns,s[o].mn1,s[o].l,s[o].r);
        s[o].sum=s[o].sum-(ll)s[o].mns*s[o].mn1+(ll)s[o].mns*mntox;
        s[o].mx1=max(s[o].mx1,s[o].mn1=mntox);
        s[o].mx2=max(s[o].mx2,mntox);
        if(s[o].mx1==mntox)s[o].mx2=-inf,s[o].mn2=inf,s[o].mxs=s[o].mns=s[o].r-s[o].l+1;
        s[o].mxtox=max(s[o].mntox=max(s[o].mntox,mntox),s[o].mxtox);
        return 0;
    }
    return 1;
}
void xadd(int& x,int y){
    if(x==inf||x==-inf)return ;
    x+=y;
}
void pushdown(int o){
    if(s[o].add){
        s[o<<1].add+=s[o].add;
        s[o<<1].sum+=(ll)s[o].add*(s[o<<1].r-s[o<<1].l+1);
        s[o<<1].mx1+=s[o].add,s[o<<1].mn1+=s[o].add;
        xadd(s[o<<1].mxtox,s[o].add),xadd(s[o<<1].mntox,s[o].add);
        xadd(s[o<<1].mx2,s[o].add),xadd(s[o<<1].mn2,s[o].add);
         
        s[o<<1|1].add+=s[o].add;
        s[o<<1|1].sum+=(ll)s[o].add*(s[o<<1|1].r-s[o<<1|1].l+1);
        s[o<<1|1].mx1+=s[o].add,s[o<<1|1].mn1+=s[o].add;
        xadd(s[o<<1|1].mxtox,s[o].add),xadd(s[o<<1|1].mntox,s[o].add);
        xadd(s[o<<1|1].mx2,s[o].add),xadd(s[o<<1|1].mn2,s[o].add);
         
        s[o].add=0;
    }
    if(s[o].mxtox!=inf){
        updmax(o<<1,s[o].mxtox);
        updmax(o<<1|1,s[o].mxtox);
        s[o].mxtox=inf;
    }
    if(s[o].mntox!=-inf){
        updmin(o<<1,s[o].mntox);
        updmin(o<<1|1,s[o].mntox);
        s[o].mntox=-inf;
    }
}
void pushup(ll o){
    int ls=o<<1,rs=o<<1|1;
    s[o].sum=s[ls].sum+s[rs].sum+(ll)s[o].add*(s[o].r-s[o].l+1);
    s[o].mx1=max(s[ls].mx1,s[rs].mx1);
    s[o].mx2=max(s[ls].mx2,s[rs].mx2);
    s[o].mxs=s[o].mns=0;
    if(s[o].mx1==s[ls].mx1)s[o].mxs+=s[ls].mxs;
    else if(s[o].mx2<s[ls].mx1)s[o].mx2=s[ls].mx1;
    if(s[o].mx1==s[rs].mx1)s[o].mxs+=s[rs].mxs;
    else if(s[o].mx2<s[rs].mx1)s[o].mx2=s[rs].mx1;
    s[o].mx1+=s[o].add;
     
    s[o].mn1=min(s[ls].mn1,s[rs].mn1);
    s[o].mn2=min(s[ls].mn2,s[rs].mn2);
    if(s[o].mn1==s[ls].mn1)s[o].mns+=s[ls].mns;
    else if(s[o].mn2>s[ls].mn1)s[o].mn2=s[ls].mn1;
    if(s[o].mn1==s[rs].mn1)s[o].mns+=s[rs].mns;
    else if(s[o].mn2>s[rs].mn1)s[o].mn2=s[rs].mn1;
    s[o].mn1+=s[o].add;
    xadd(s[o].mn2,s[o].add);
    xadd(s[o].mx2,s[o].add);
}
void build(int o,int l,int r){
    s[o].l=l,s[o].r=r;
    s[o].clear();
    if(l==r){
        s[o].mx1=s[o].mn1=a[l];
        s[o].mxs=1,s[o].mns=1;
        s[o].sum=a[l];
        return ;
    }
    int mid=l+r>>1;
    build(o<<1,l,mid);
    build(o<<1|1,mid+1,r);
    pushup(o);
}
void modify1(int o,int ql,int qr,int a){
    if(ql<=s[o].l&&s[o].r<=qr){
        s[o].sum+=(ll)(s[o].r-s[o].l+1)*a;
        s[o].mx1+=a,s[o].mxtox+=a;
        s[o].mn1+=a,s[o].mntox+=a;
        xadd(s[o].mx2,a);
        xadd(s[o].mn2,a);
        s[o].add+=a;
        return ;
    }
    pushdown(o);
    if(ql<=s[o<<1].r)modify1(o<<1,ql,qr,a);
    if(s[o<<1|1].l<=qr)modify1(o<<1|1,ql,qr,a);
    pushup(o);
}
void modify2(ll o,ll ql,ll qr,ll a){
    if(ql<=s[o].l&&s[o].r<=qr&&!updmin(o,a))
        return ;
    pushdown(o);
    if(ql<=s[o<<1].r)modify2(o<<1,ql,qr,a);
    if(s[o<<1|1].l<=qr)modify2(o<<1|1,ql,qr,a);  
    pushup(o);
}
void modify3(ll o,ll ql,ll qr,ll a){
//  printf("[%d,%d,%d]",s[o].l,s[o].r,s[o].mx1);
    if(ql<=s[o].l&&s[o].r<=qr&&!updmax(o,a))
        return ;
    pushdown(o);
    if(ql<=s[o<<1].r)modify3(o<<1,ql,qr,a);
    if(s[o<<1|1].l<=qr)modify3(o<<1|1,ql,qr,a);
    pushup(o);
}
ll querysum(int o,int ql,int qr){
    if(ql<=s[o].l&&s[o].r<=qr)return s[o].sum;
    pushdown(o);
    ll ans=0;
    if(ql<=s[o<<1].r)ans+=querysum(o<<1,ql,qr);
    if(s[o<<1|1].l<=qr)ans+=querysum(o<<1|1,ql,qr);
    return ans;
}
int querymx(int o,int ql,int qr){
    if(ql<=s[o].l&&s[o].r<=qr)return s[o].mx1;
    pushdown(o);
    int ans=-inf;
    if(ql<=s[o<<1].r)ans=max(ans,querymx(o<<1,ql,qr));
    if(s[o<<1|1].l<=qr)ans=max(ans,querymx(o<<1|1,ql,qr));
    return ans;
}
int querymn(int o,int ql,int qr){
    if(ql<=s[o].l&&s[o].r<=qr)return s[o].mn1;
    pushdown(o);
    int ans=inf;
    if(ql<=s[o<<1].r)ans=min(ans,querymn(o<<1,ql,qr));
    if(s[o<<1|1].l<=qr)ans=min(ans,querymn(o<<1|1,ql,qr));
    return ans;
}
int main(){
    n=read();
    for(int i=1;i<=n;++i)a[i]=read();
    build(1,1,n);
    m=read(); 
    for(int i=1;i<=m;++i){
        int tp,l,r,x;tp=read();
        if(tp<=3)l=read(),r=read(),x=read();
        else l=read(),r=read();
        if(tp==1)modify1(1,l,r,x);
        else if(tp==2)modify2(1,l,r,x);
        else if(tp==3)modify3(1,l,r,x);
        else if(tp==4)printf("%lld\n",querysum(1,l,r));
        else if(tp==5)printf("%d\n",querymx(1,l,r));
        else if(tp==6)printf("%d\n",querymn(1,l,r));
//      printf("[%d:%d]\n",s[1].mn1,s[1].sum);
//      printf("[ok]");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值