Can you answer these queries II 线段树(区间的区间更新)

Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse to write two program of same kind at all. So he always failes in contests.

When having a contest, Yang Zhe looks at the score of every problems first. For the problems of the same score, Yang Zhe will do only one of them. If he’s lucky enough, he can get all the scores wanted.

Amber is going to hold a contest in SPOJ. She has made a list of N candidate problems, which fit Yang Zhe very well. So Yang Zhe can solve any problem he want. Amber lined up the problems, began to select. She will select a subsequence of the list as the final problems. Being A girl of great compassion, she’d like to select such a subsequence (can be empty) that Yang Zhe will get the maximal score over all the possible subsequences.

Amber found the subsequence easily after a few minutes. To make things harder, Amber decided that, Yang Zhe can take this contest only if Yang Zhe can answer her Q questions. The question is: if the final problems are limited to be a subsequence of list[X..Y] (1 <= X <= Y <= N), what’s the maximal possible score Yang Zhe can get?

As we know, Yang Zhe is a bit idiot (so why did he solve the problem with a negative score?), he got Wrong Answer again… Tell him the correct answer!

Input

Line 1: integer N (1 <= N <= 100000);
Line 2: N integers denoting the score of each problem, each of them is a integer in range [-100000, 100000];
Line 3: integer Q (1 <= Q <= 100000);
Line 3+i (1 <= i <= Q): two integers X and Y denoting the ith question.
Output

Line i: a single integer, the answer to the ith question.
Example

Input:
9
4 -2 -2 3 -1 -4 2 2 -6
3
1 2
1 5
4 9

Output:
4
5
3

这里写图片描述
一个大佬的代码。。作为菜鸟的我 解读了一遍。。
叶子是区间。。每次插入一个值,相当于往前面所有(不含当前元素的)区间都插入了一个新的数

#include <bits/stdc++.h>
#define lc rt<<1
#define rc rt<<1|1
using namespace std;
typedef long long LL;
const LL kMaxN = 110000;
LL n,m;
LL arr[kMaxN*2];
LL pre[kMaxN*2];
LL ans[kMaxN];
struct A
{
  LL l,r,id;
  bool operator < (const A &b) const 
  {
    return r<b.r;
  }
}itv[kMaxN];

struct SegTree{
  LL lazy,prelazy;
  LL sum,presum;
}tr[kMaxN<<2];

void pushup(LL rt)
{
  tr[rt].presum=max(tr[lc].presum,tr[rc].presum);
  tr[rt].sum=max(tr[lc].sum,tr[rc].sum);
}
void pushdown(LL rt)
{
  if(!tr[rt].lazy&&!tr[rt].prelazy) return ;
  tr[lc].presum=max(tr[lc].presum,tr[lc].sum+tr[rt].prelazy); //左子树的最大和
  tr[lc].prelazy=max(tr[lc].prelazy,tr[lc].lazy+tr[rt].prelazy); //左子树的最大延迟
  tr[lc].sum+=tr[rt].lazy,tr[lc].lazy+=tr[rt].lazy;   //本来就是一个连续的区间
 //叶子不是元素的值而是区间和。
  tr[rc].presum=max(tr[rc].presum,tr[rc].sum+tr[rt].prelazy);
  tr[rc].prelazy=max(tr[rc].prelazy,tr[rc].lazy+tr[rt].prelazy); //子树的最大延迟加上树根的和延迟
  //lazy是新的,prelazy是旧的,现在就是考虑是否更新旧的延迟,也就是是否将这段的新元素纳入。
  tr[rc].sum+=tr[rt].lazy,tr[rc].lazy+=tr[rt].lazy;    
  //在pushdown里面四个一起更新
  //更新以后延迟变0
  tr[rt].lazy=tr[rt].prelazy=0;
}


void update(LL L,LL R,LL add,LL l,LL r,LL rt)
{
  if(L<=l&&R>=r)
  {
    tr[rt].sum+=add; //sum 旧区间加上新的数
    tr[rt].lazy+=add; //lazy 就是一个区间加上一个数得到另一个区间
    tr[rt].prelazy=max(tr[rt].prelazy,tr[rt].lazy); //prelazy 是其以前最大的递增数
    tr[rt].presum=max(tr[rt].presum,tr[rt].sum); //presum是这个区间的最大和
    return ;
  }
  pushdown(rt);
  LL m=(l+r)>>1;
  if(L<=m)
    update(L,R,add,l,m,lc);
  if(R>m)
    update(L,R,add,m+1,r,rc);
  pushup(rt);
}

LL query(LL L,LL R,LL l,LL r,LL rt)
{
  if(L<=l&&R>=r) return tr[rt].presum;
  pushdown(rt);
  LL m=(l+r)>>1;
  LL ans=0;
  if(L<=m)
    ans=max(ans,query(L,R,l,m,lc)); //不是相加而是求最大值,是因为被问题区间被切开
  if(R>m)
    ans=max(ans,query(L,R,m+1,r,rc));
  return ans;
}

int main()
{
  scanf("%lld",&n);
  for(LL i = 1;i<=n;i++)
    scanf("%lld",&arr[i]);
  scanf("%lld",&m);
  for(LL i=0;i<m;i++)
  {
    scanf("%lld%lld",&itv[i].l,&itv[i].r),itv[i].id=i;
  }
  sort(itv,itv+m);
  LL now =0;
  //核心算法区间更新。
  //叶子不是元素值是区间和
  for(LL i=1;i<=n;i++)
  {
    update(pre[arr[i]+kMaxN]+1,i,arr[i],1,n,1);//前面两个变量是应该更新的区间。
    pre[arr[i]+kMaxN] = i;                     //运用pre数组加1,如果是两个相同的数但是因为区间不一样,所以更新的是两个不同的点
    while(now<m&&itv[now].r==i)
    {
      ans[itv[now].id]=query(itv[now].l,itv[now].r,1,n,1);
      now++;
    }
  }
  for(LL i=0;i<m;i++) printf("%lld\n",ans[i] );
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值