upc 最⼤⼦段和 线段树 + 懒标

最⼤⼦段和
时间限制: 1 Sec 内存限制: 128 MB
题目描述
现在给你⼀个序列a1…an,求⼀个权值和最⼤的区间(区间可以为空),其中相同的数只算⼀次。
输入
第⼀⾏⼀个正整数n,
接下来⼀⾏n个整数,a1到an。
输出
⼀⾏⼀个整数表⽰答案。
样例输入 Copy
【样例1】
5
1 -3 2 2 -4
【样例2】
5
4 -2 0 -2 3
样例输出 Copy
【样例1】
2
【样例2】
5
提示
对于100%的数据,n≤200000,|ai|≤108

师傅巨巨给的思路,orz。
考虑用线段树维护一段连续区间,假设这个连续区间用 b [ j ] 表示,b [ j ] 表示 a [ j ] ~ a [ i ] 的连续区间,i 是当前枚举到的数,从 1 ~ n 枚举,也就是说线段树维护的是一段区间,并不是位置

枚举的时候分以下两种情况
(1)当前 a [ i ] 在之前没有出现过的时候,那么直接将 1 ~ i 用线段树存的区间结尾都加上 a [ i ] ,并更新 a [ i ] 出现的位置。
(2)当前 a [ i ] 在之前 pos 这个位置出现过,那么 pos + 1 ~ i 加上 a [ i ],并更新位置,也就是 b [ pos + 1 ] ~ b [ i ] 的区间都加 a [ i ] 。

让后线段树每个结点需要存 sum ,lazy ,msum ,mlazy,sum是存的当前区间的和,msum存的是当前区间最大子段和,lazy是懒标,mlazy是懒标的最大子段和。

除了pushdown操作其他的都很简单,跟普通的线段树一样,讲一下pushdown。
(1)更新 msum 的时候,儿子的 sum + 父亲的 mlazy ,不用子区间 msum 来更新是因为儿子 msum 不一定能和父亲的 mlazy 接起来。
(2)更新 mlazy 的时候,儿子的 lazy + 父亲的 mlazy ,这个理解方式跟(1)一样,因为lazy也算是一个连续区间,而儿子的 mlazy 不一定能跟父亲的 mlazy 接起来。
(3)对于儿子的 sum 和 lazy ,直接把懒标接在后面即可。

其他的实现具体可以看代码。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N=200010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n;
int a[N];
map<int,int>mp;
struct Node
{
    int l,r;
    LL sum,lazy;
    LL msum,mlazy;
}tr[N<<2];

void pushup(int u)
{
    tr[u].sum=max(tr[L].sum,tr[R].sum);//因为sum存的是区间和,两个区间应该取max,而非相加。
    tr[u].msum=max(tr[L].msum,tr[R].msum);
}

void pushdown(int u)
{
    if(tr[u].lazy==0&&tr[u].mlazy==0) return;
    LL &lazy=tr[u].lazy,&mlazy=tr[u].mlazy;
    tr[L].msum=max(tr[L].msum,tr[L].sum+mlazy);//更新最大子段
    tr[R].msum=max(tr[R].msum,tr[R].sum+mlazy);
    tr[L].mlazy=max(tr[L].mlazy,tr[L].lazy+mlazy);//更新懒标的最大子段
    tr[R].mlazy=max(tr[R].mlazy,tr[R].lazy+mlazy);
    tr[L].lazy+=lazy,tr[R].lazy+=lazy;//更新懒标
    tr[L].sum+=lazy,tr[R].sum+=lazy;//更新区间和
    tr[u].lazy=tr[u].mlazy=0;//清零
}

void build(int u,int l,int r)
{
    tr[u]={l,r,0,0,0,0};
    if(l==r) return;
    build(L,l,Mid),build(R,Mid+1,r);
}

void modify(int u,int l,int r,int c)
{
    if(tr[u].l>=l&&tr[u].r<=r)
    {
        tr[u].sum+=c;
        tr[u].msum=max(tr[u].msum,tr[u].sum);
        tr[u].lazy+=c;
        tr[u].mlazy=max(tr[u].mlazy,tr[u].lazy);
        return;
    }
    pushdown(u);
    if(l<=Mid) modify(L,l,r,c);
    if(r>Mid) modify(R,l,r,c);
    pushup(u);
}

LL query(int u,int l,int r)
{
    if(tr[u].l>=l&&tr[u].r<=r)
        return tr[u].msum;
    pushdown(u);
    LL ans=0;
    if(l<=Mid) ans=max(ans,query(L,l,r));
    if(r>Mid) ans=max(ans,query(R,l,r));
    return ans;
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    LL ans=0;
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,1,n);
    for(int i=1;i<=n;i++)
    {
        modify(1,mp[a[i]]+1,i,a[i]);
        mp[a[i]]=i;//更新位置
        ans=max(ans,query(1,1,i));
    }
    printf("%lld\n",ans);





	return 0;
}

猜你喜欢

转载自blog.csdn.net/DaNIelLAk/article/details/106081948
UPC
今日推荐