SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)

GSS2 - Can you answer these queries II

#tree

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

Warning: large input/output data,be careful with certain languages

【题意】

给出A[1],A[2]...,A[N], 有Q次询问,每次询问包含x,y,

需要回答Max{a[i]+a[i+1]+...+a[j]; x <= i <= j <= y},相同的数只能计算一次。

看到题目还以为是DP,根本没往线段树上想,看了题解感觉好神奇啊。。。

先将查询区间离线并且排序(类似莫队算法),然后循环 i =1~n,对于每一个a[i],插入进线段树更新节点。而线段树的每一个节点维护四个数组。sum[rt]表示以a[i]结尾的

最大的后缀和,presum[rt]表示1,~n中最大的区间和(a[j]+...+a[k],1<=j<=k<=i),lazy[rt]为懒惰标记,做过区间修改的应该知道,prelazy[rt]则为此区间最大的lazy。

然后就是线段树的事了。代码不难,应该很好理解,虽然我花了两天才看懂=_=

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define met(a,b) memset(a,b,sizeof a)
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N=2e5+50;
const int M=N*N+10;
ll a[N];
ll num,m,n,tot=0;
ll sum[N*2],presum[N*2],ans[N];
ll lazy[N*2],prelazy[N*2],pre[N*2];
struct man{
    ll l,r,id;
    bool operator < (const man & b) const {
        return r < b.r;
    }
}q[N];
void Push_down(int rt) {
    if(lazy[rt]||prelazy[rt]) {
        presum[rt*2]=max(presum[rt*2],sum[rt*2]+prelazy[rt]);
        prelazy[rt*2]=max(prelazy[rt*2],lazy[rt*2]+prelazy[rt]);
        sum[rt*2]+=lazy[rt];lazy[rt*2]+=lazy[rt];

        presum[rt*2+1]=max(presum[rt*2+1],sum[rt*2+1]+prelazy[rt]);
        prelazy[rt*2+1]=max(prelazy[rt*2+1],lazy[rt*2+1]+prelazy[rt]);
        sum[rt*2+1]+=lazy[rt];lazy[rt*2+1]+=lazy[rt];
        lazy[rt]=prelazy[rt]=0;
    }
}
void Push_up(ll rt){
    presum[rt]=max(presum[rt*2],presum[rt*2+1]);
    sum[rt]=max(sum[rt*2],sum[2*rt+1]);
}
void Update(ll L,ll R,ll l,ll r,ll rt,ll add) {
    if(l>=L&&r<=R) {
        lazy[rt]+=add;
        sum[rt]+=add;
        prelazy[rt]=max(prelazy[rt],lazy[rt]);
        presum[rt]=max(presum[rt],sum[rt]);
        return;
    }
    Push_down(rt);
    ll m=(r+l)>>1;
    if(L<=m)Update(L,R,lson,add);
    if(R>m) Update(L,R,rson,add);
    Push_up(rt);
}
ll Query(ll L,ll R,ll l,ll r,ll rt) {
    if(L<=l&&r<=R)return presum[rt];
    Push_down(rt);
    ll m=(l+r)>>1,ans=-100000000000;
    if(L<=m)ans=max(ans,Query(L,R,lson));
    if(R>m)ans=max(ans,Query(L,R,rson));
    return ans;
}

int main() {
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    scanf("%lld",&m);
    for(int i=0;i<m;i++){
        scanf("%lld%lld",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q,q+m);
    ll cnt=0;
    for(int i=1;i<=n;i++){
        Update(pre[a[i]+N]+1,i,1,n,1,a[i]);
        pre[a[i]+N]=i;
        while(cnt<m&&q[cnt].r==i){
            ans[q[cnt].id]=Query(q[cnt].l,q[cnt].r,1,n,1);
            cnt++;
        }
    }
    for(int i=0;i<m;i++)printf("%lld ",ans[i]);printf("\n");
    return 0;
}
时间: 2024-12-26 03:32:59

SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)的相关文章

bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树

2482: [Spoj1557] Can you answer these queries II Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 145  Solved: 76[Submit][Status][Discuss] Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和(可选空子段). 这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次. 比如:1,2,3,2,2,2出现了3次,但只算一次,

SPOJ 1557. Can you answer these queries II 线段树

Can you answer these queries II Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://www.spoj.com/problems/GSS2/ Description Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse

Spoj 1557 Can you answer these queries II 线段树 任意区间最大子段和 不重复数字

题目链接:点击打开链接 每个点都是最大值,把一整个序列和都压缩在一个点里. #include <vector> #include <iostream> #include <algorithm> #include <string.h> #include <stdio.h> using namespace std; #define N 100005 #define Lson(x) (x<<1) #define Rson(x) (x<

Spoj 1716 Can you answer these queries III 线段树 单点修改 区间求最大子段和

题目链接:点击打开链接 == 原来写1的时候已经把更新函数写好了.. #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <map> using namespace std; #define N 50050 #define Lso

spoj gss2 : Can you answer these queries II 离线&amp;&amp;线段树

1557. Can you answer these queries II Problem code: GSS2 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 co

SPOJ GSS3 Can you answer these queries III (线段树)

题目大意: 求区间最大子区间的和. 思路分析: 记录左最大,右最大,区间最大. 注意Q_L  和 Q_R  就好. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e #define maxn 55555 using na

SPOJ GSS4 Can you answer these queries IV (线段树)

题目大意: 给出N个数 0     操作   把 l -----  r之间的数全部开平方 1     操作  输出 l -----r  之间的和 思路分析: 判断区间里的数字是否全相同.如果相同, 将cov 置为该数 查询的时候和更新的时候,如果碰到cov != -1 的  就直接返回就可以了 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #incl

【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树

[BZOJ2482][Spoj1557] Can you answer these queries II Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和(可选空子段). 这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次. 比如:1,2,3,2,2,2出现了3次,但只算一次,于是这个序列的和是1+2+3=6. Input 第一行一个数n. 第二行n个数,为给定的序列,这些数的绝对值小于等于100000. 第三行一个数m. 接下来m行,每行两个

HDU 4027 Can you answer these queries? (线段树区间求和)

Can you answer these queries? Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 12290    Accepted Submission(s): 2912 Problem Description A lot of battleships of evil are arranged in a line before