HDU 5306Gorgeous Sequence (吉司机线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5306

题目大意:给你n个数,你有3种操作,操作如下:

$0,x,y,v$,对区间$a[x]-a[y]$取$min(v,a[i])$

$1,x,y$,询问区间最大值

$2,x,y$,询问区间和

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

吉司机线段树,通常就是比正常的线段树多维护了个次的东西,比若说这题,我们可以维护一个次大值,如果该区间的最大值小于修改的v,那么直接return,如果大于次大值,那么也就是说只有最大值需要修改,那么我们记录一下最大值的个数,修改的时候我们直接对sum+(最大值-val)乘上最大值的数量就好了,然后将该区间的最大值修改为val,然后开始push_down了,如下所示:

void solve(int rt,int val)
{
    if (val>=tree[rt].mx) return;
    tree[rt].sum+=1LL*(val-tree[rt].mx)*tree[rt].mxnb;
    tree[rt].mx=val;
}

void push_down(int rt)
{
    solve(lc,tree[rt].mx);solve(rc,tree[rt].mx);
}

void update(int l,int r,int rt,int L,int R,int val)
{
    if (val>=tree[rt].mx) return;
    if (l>=L && r<=R && val>tree[rt].cimx){
        solve(rt,val);
        return;
    }
    int mid=(l+r)>>1; 
    push_down(rt);
    if (mid>=L) update(lson,L,R,val);
    if (mid<R) update(rson,L,R,val);
    push_up(rt);
}

这样看起来似乎复杂度还是有点高,但对于随机数据来讲,他的平均复杂度还是不错的

以下是AC代码:

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;

#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lc rt<<1
#define rc rt<<1|1
typedef long long ll;
const int mac=1e6+10;

struct node
{
    int mx,cimx,mxnb;
    ll sum;
}tree[mac<<2];

void push_up(int rt)
{
    tree[rt].sum=tree[lc].sum+tree[rc].sum;
    if (tree[lc].mx==tree[rc].mx){
        tree[rt].mx=tree[lc].mx;
        tree[rt].mxnb=tree[lc].mxnb+tree[rc].mxnb;
        tree[rt].cimx=max(tree[lc].cimx,tree[rc].cimx);
    }
    else {
        if (tree[lc].mx>tree[rc].mx) {
            tree[rt].mxnb=tree[lc].mxnb;
            tree[rt].cimx=max(tree[rc].mx,tree[lc].cimx);
        }
        else {
            tree[rt].mxnb=tree[rc].mxnb;
            tree[rt].cimx=max(tree[lc].mx,tree[rc].cimx);
        }
        tree[rt].mx=max(tree[lc].mx,tree[rc].mx);
    }
}

void solve(int rt,int val)
{
    if (val>=tree[rt].mx) return;
    tree[rt].sum+=1LL*(val-tree[rt].mx)*tree[rt].mxnb;
    tree[rt].mx=val;
}

void push_down(int rt)
{
    solve(lc,tree[rt].mx);solve(rc,tree[rt].mx);
}

void build(int l,int r,int rt)
{
    tree[rt].cimx=-1;
    if (l==r){
        int x;
        scanf ("%d",&x);
        tree[rt].mx=tree[rt].sum=x;
        tree[rt].mxnb=1;
        return;
    }
    int mid=(l+r)>>1;
    build(lson);build(rson);
    push_up(rt);
}

void update(int l,int r,int rt,int L,int R,int val)
{
    if (val>=tree[rt].mx) return;
    if (l>=L && r<=R && val>tree[rt].cimx){
        solve(rt,val);
        return;
    }
    int mid=(l+r)>>1; 
    push_down(rt);
    if (mid>=L) update(lson,L,R,val);
    if (mid<R) update(rson,L,R,val);
    push_up(rt);
}

ll query(int l,int r,int rt,int L,int R,int id)
{
    ll ans=0;
    if (l>=L && r<=R) {
        if (!id) return 1LL*tree[rt].mx;
        else return tree[rt].sum;
    }
    push_down(rt);
    int mid=(l+r)>>1;
    if (mid>=L) {
        if (!id) ans=max(ans,query(lson,L,R,id));
        else ans+=query(lson,L,R,id);
    }
    if (mid<R) {
        if (!id) ans=max(ans,query(rson,L,R,id));
        else ans+=query(rson,L,R,id);
    }
    return ans;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int t;
    scanf ("%d",&t);
    while (t--){
        int n,q;
        scanf ("%d%d",&n,&q);
        build(1,n,1);
        while (q--){
            int opt,l,r,v;
            scanf ("%d%d%d",&opt,&l,&r);
            if (!opt) {
                scanf ("%d",&v);
                update(1,n,1,l,r,v);
            }
            else if (opt==1) printf("%lld
",query(1,n,1,l,r,0));
            else printf("%lld
",query(1,n,1,l,r,1));
        }
    }
    return 0;
}
路漫漫兮
原文地址:https://www.cnblogs.com/lonely-wind-/p/13275773.html