[HDU] 5306 Gorgeous Sequence [区间取min&求和&求max][线段树]

Problem Description
There is a sequence a of length n. We use ai to denote the i-th element in this sequence. You should do the following three types of operations to this sequence.

0 x y t: For every x≤i≤y, we use min(ai,t) to replace the original ai’s value.
1 x y: Print the maximum value of ai that x≤i≤y.
2 x y: Print the sum of ai that x≤i≤y.

Input
The first line of the input is a single integer T, indicating the number of testcases.

The first line contains two integers n and m denoting the length of the sequence and the number of operations.

The second line contains n separated integers a1,…,an (∀1≤i≤n,0≤ai<231).

Each of the following m lines represents one operation (1≤x≤y≤n,0≤t<231).

It is guaranteed that T=100, ∑n≤1000000, ∑m≤1000000.

Output
For every operation of type 1 or 2, print one line containing the answer to the corresponding query.

Sample Input
1
5 5
1 2 3 4 5
1 1 5
2 1 5
0 3 5 3
1 1 5
2 1 5

Sample Output
5
15
3
12

解题报告

我们对于线段树的每个结点,维护最大值max,最大值出现次数cnt,严格次大值sec和区间和sum。

修改时,对于可修改结点k,若

  1. t≥max(k):修改对于该区间无效,返回。

  2. sec(k) < t < max(k):t只对max(k)发生影响,令max(k)=t并更新区间和,返回。

  3. sec(k) ≤ t:无法简单地更新区间和了……

复杂度是 (mlog n),证明的话可以参看16年集训队吉爷的论文

这个题要优化输入输出,否则可能超时

原题链接

#include
#include
#include
#define MAX_N 1000005
using namespace std;
typedef long long LL;

const int MAXS = 40*1024*1024;
char buf[MAXS],bufout[MAXS],*ch,*chout;

void read(int &x){
    for(++ch;*ch<=32;++ch);
    for(x=0;*ch>='0';++ch) x=x*10+*ch-'0';
}

void out(int x){
    if(!x) *(++chout)='0';
    else{
        char *ch0=chout,*ch1=chout+1;
        while(x){
            *(++ch0)=x%10+'0';
            x/=10;
        }
        chout=ch0;
        while(ch1<=ch0) swap(*(ch1++),*(ch0--));
    }
    *(++chout)='\n';
}

void out(long long x){
    if(!x) *(++chout)='0';
    else{
        char *ch0=chout,*ch1=chout+1;
        while(x){
            *(++ch0)=x%10+'0';
            x/=10;
        }
        chout=ch0;
        while(ch1<=ch0) swap(*(ch1++),*(ch0--));
    }
    *(++chout)='\n';
}

void std_init(){
    ch=buf-1;
    chout=bufout-1;
    fread(buf,1,MAXS,stdin);
}

void std_out(){
    fwrite(bufout,1,chout-bufout+1,stdout);
}

/*---------------------------------------------------------------*/

struct node{LL sum;int _max,sa,cum;};//和 最大值 次大值 最大值数量

node dat[MAX_N*2+100];
int res[MAX_N];

void maintain(int k){
    int tmpk=k<<1;
    dat[k].sum=dat[tmpk].sum+dat[tmpk|1].sum;
    dat[k].sa=max(dat[tmpk].sa,dat[tmpk|1].sa);
    if(dat[tmpk]._max>dat[tmpk|1]._max){
        dat[k]._max=dat[tmpk]._max;
        dat[k].cum=dat[tmpk].cum;
        if(dat[tmpk|1]._max>dat[k].sa) dat[k].sa=dat[tmpk|1]._max;
    }else if(dat[tmpk]._max1]._max){
        dat[k]._max=dat[tmpk|1]._max;
        dat[k].cum=dat[tmpk|1].cum;
        if(dat[tmpk]._max>dat[k].sa) dat[k].sa=dat[tmpk]._max;
    }else{
        dat[k]._max=dat[tmpk]._max;
        dat[k].cum=dat[tmpk].cum+dat[tmpk|1].cum;
    }
}

void dec(int k,int t){
    if(t>=dat[k]._max) return ;
    dat[k].sum-=1LL*(dat[k]._max-t)*dat[k].cum;
    dat[k]._max=t;
}

void pushdown(int k){
    dec(k<<1,dat[k]._max);
    dec(k<<1|1,dat[k]._max);
}

void build(int k,int l,int r){
    if(l==r) dat[k].sum=dat[k]._max=res[l],dat[k].cum=1,dat[k].sa=-1;
    else{
        int mid=r+l>>1,tmpk=2*k;
        build(tmpk,l,mid);
        build(tmpk+1,mid+1,r);
        maintain(k);
    }
}

void change(int k,int l,int r,int ql,int qr,int t){
    if(l>qr||rreturn ;
    if(r<=qr&&l>=ql&&t>dat[k].sa){
        dec(k,t); return ;
    }
    pushdown(k);
    int mid=r+l>>1,tmpk=2*k;
    change(tmpk,l,mid,ql,qr,t);
    change(tmpk+1,mid+1,r,ql,qr,t);
    maintain(k);
}

int query1(int k,int l,int r,int ql,int qr){
    if(l>qr||rreturn 0;
    if(r<=qr&&l>=ql) return dat[k]._max;
    pushdown(k);
    int mid=l+r>>1,tmpk=2*k;
    return max(query1(tmpk,l,mid,ql,qr),query1(tmpk+1,mid+1,r,ql,qr));
}

LL query2(int k,int l,int r,int ql,int qr){
    if(l>qr||rreturn 0;
    if(r<=qr&&l>=ql) return dat[k].sum;
    pushdown(k);
    int mid=l+r>>1,tmpk=2*k;
    return query2(tmpk,l,mid,ql,qr)+query2(tmpk+1,mid+1,r,ql,qr);
}

int main()
{
    std_init();
    int T;
    read(T);
    for(int t=1;t<=T;t++){
        int n,m;
        read(n);read(m);
        for(int i=1;i<=n;i++)
            read(res[i]);
        build(1,1,n);
        while(m--){
            int op,x,y;
            read(op);read(x);read(y);
            if(op) out(op==1?query1(1,1,n,x,y):query2(1,1,n,x,y));
            else{
                int val;read(val);
                change(1,1,n,x,y,val);
            }
        }
    }
    std_out();
    return 0;
}

你可能感兴趣的:(线段树)