SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)
Posted 贱人方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)相关的知识,希望对你有一定的参考价值。
GSS2 - 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 3Warning: 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; }
以上是关于SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)的主要内容,如果未能解决你的问题,请参考以下文章
SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)
SPOJ - GSS2Can you answer these queries II(线段树)
SPOJ1557 GSS2 Can you answer these queries II 线段树
spoj GSS4 - Can you answer these queries IV