Gorgeous Sequence——线段树(lazy思想+思维拓展)

这道线段树的题目真的是超级酸爽!!!

大概题意是这样的,输入1,x,y代表输出x~y的最大值。2,x,y代表输出x~y这段区间的总和。0,x,y,t代表将x~y这段区间中值更改为min(a[i],t)。难点就在第三种情况。可以看出,数据范围10^6,普通线段树的算法解决,区间更新的算法解决不了,因为有的修改有的不改,但是递归到叶子进行修改肯定超时。这时就诞生出了很麻烦的感觉。于是题解大法由此诞生。感觉这种方法超级炫酷了,至少我没看题解的话就不会想到。

就是这样想。首先是这样的,线段树的特点就是维护某一段的特征,那么这道题的目的是求一段区间的max和sum,在更新过程中max是很容易就可以维护的。在更新的时候,很显然,如果这段区间的最大值max都比t要小,那么这段肯定就不用再被修改了,直接return就好了;另一种情况就是有的大,有的小,那么我们想到,线段树是依次向下分支找寻,能不能简单点,利用前边着一个结论呢。由此我们就想到可以维护一个最大值max和次大值second,当 t 比 max 小,但是比 second 大的时候,此时最大值max就要被替换成 t ,而且无需再往下进行更新了,因为没有必要了,直接return就好了;否则的话就要pushdown,让当前id的左右子树的特征(当前id区间的max【id】,second【id】,sum【id】,以及最大值的个数geshu[i])进行修改。在pushdown的时候,reuturn到了适合的id后,我们再pushup,因为id的特征变化是由下边两个所决定的,所以一定要进行这一步操作。这样事实上该修改的特征值都修改了,也是对lazy的一种用法。然后求最大值的时候一定要pushdown,不明白的话就研究一下lazy标记。然后就是正常的查最大值,和了。

还有就是求和的时候,简单方法就是算出最大值的个数,然后进行计算。具体看代码

ps:这道题中间有种种bug,其中在更新次大值的时候,极其容易将mx【id*2】和mx【id*2+1】进行大小比较,小的那一个作为次大值。但是事实上这样子是错误的,因为很可能mx大的,但是次大值se也比另一个mx要大,所以要都比较一边。

还有一个易错的地方,就是因为给的数据太大了,在计算sun的时候,sum[id]=sum[id]-geshu[id]*(mx[id]-t);将括号拆开写反而会WA ,因为超longlong了,这个地方也算是一个坑吧,我深陷此坑~

代码:

#include<bits/stdc++.h>
using namespace std;

#define lson id*2,l,(l+r)/2
#define rson id*2+1,(l+r)/2+1,r
const int maxn=1000000+10;
long long  se[maxn*4],mx[maxn*4];
long long a[maxn];
long long sum[maxn*4];
int geshu[maxn*4];

void pushup(int id)
{
    sum[id]=sum[id*2]+sum[id*2+1];
    mx[id]=max(mx[id*2],mx[id*2+1]);
    if(mx[id*2]>mx[id*2+1])
    {
        ///se[id]=mx[id*2+1];///这个地方是错的!!!!
        se[id]=max(se[id*2],mx[id*2+1]);
        geshu[id]=geshu[id*2];
    }
    else if(mx[id*2]==mx[id*2+1])
    {
        if(se[id*2]>se[id*2+1])
            se[id]=se[id*2];
        else if(se[id*2]<se[id*2+1])
            se[id]=se[id*2+1];
        else
            se[id]=se[id*2];
        geshu[id]=geshu[id*2]+geshu[id*2+1];
    }
    else
    {
        ///se[id]=mx[id*2];是错的!!!
        se[id]=max(mx[id*2],se[id*2+1]);
        geshu[id]=geshu[id*2+1];
    }
}

void build(int id,int l,int r)
{
    if(l==r)
    {
        mx[id]=a[l];
        se[id]=-1;
        sum[id]=a[l];
        geshu[id]=1;
        return ;
    }
    build(id*2, l, (l+r)/2);
    build(id*2+1,(l+r)/2+1,r);
    pushup(id);
}

void putTag(int id,int t)
{
    if (t>= mx[id])
        return;
    sum[id]=sum[id]-geshu[id]*(mx[id]-t);
    mx[id]=t;
}

void pushdown(int id)
{
    putTag(id*2,mx[id]);
    putTag(id*2+1,mx[id]);
}

void change(int L,int R,int id,int l,int r,int t)
{
    if(t>mx[id])
        return;
    if(L<=l &&R>=r && t>se[id])
    {
        putTag(id,t);
        return;
    }
    pushdown(id);
    if(L<=(l+r)/2)
        change(L,R,id*2,l,(l+r)/2,t);
    if(R>(l+r)/2)
        change(L,R,id*2+1,(l+r)/2+1,r,t);
    pushup(id);
}
int chaxun_max(int L,int R,int id,int l,int r)
{
    if(L<=l &&R>=r )
        return mx[id];
    pushdown(id);
    int ans=0;
    if(L<=(l+r)/2)
        ans=chaxun_max(L,R,lson);
    if(R>(l+r)/2)
        ans=max(ans,chaxun_max(L,R,rson));
    return ans;
}

long long chaxun_sum(int L,int R,int id,int l,int r)
{
    if(L<=l && R>=r)
        return sum[id];
    pushdown(id);
    long long sum=0;
    if(L<=(l+r)/2)
        sum+=chaxun_sum(L,R,lson);
    if(R>(l+r)/2)
        sum+=chaxun_sum(L,R,rson);
    return sum;
}

int main()
{
    int T;
    int n,m;
    int x,y,c,e;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
        }
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
           scanf("%d",&e);
           if(e==1)
           {
               scanf("%d%d",&x,&y);
               cout<<chaxun_max(x,y,1,1,n)<<endl;
           }
           else if(e==2)
           {
               scanf("%d%d",&x,&y);
               cout<<chaxun_sum(x,y,1,1,n)<<endl;
           }
           else
           {
               scanf("%d%d%d",&x,&y,&c);
               change(x,y,1,1,n,c);
           }
        }
    }
    return 0;
}

Gorgeous Sequence

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 4554    Accepted Submission(s): 1232


 

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.

x y t: For every xiy, we use min(ai,t) to replace the original ai's value.
x y: Print the maximum value of ai that xiy.
x y: Print the sum of ai that xiy.

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≤in,0≤ai<231).

Each of the following m lines represents one operation (1≤xyn,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

Hint

Please use efficient IO method

Author

XJZX

Source

2015 Multi-University Training Contest 2

Recommend

wange2014   |   We have carefully selected several similar problems for you:  6297 6296 6295 6294 6293 

猜你喜欢

转载自blog.csdn.net/xianpingping/article/details/81104786
今日推荐