GSS1 - Can you answer these queries I
You are given a sequence A[1], A[2], ..., A[N] . ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000 ). A query is defined as follows:
Query(x,y) = Max { a[i]+a[i+1]+...+a[j] ; x ≤ i ≤ j ≤ y }.
Given M queries, your program must output the results of these queries.
Input
- The first line of the input file contains the integer N.
- In the second line, N numbers follow.
- The third line contains the integer M.
- M lines follow, where line i contains 2 numbers xi and yi.
Output
Your program should output the results of the M queries, one query per line.
Example
Input:
3
-1 2 3
1
1 2
Output:
2
解题思路:这一题。。。我是真不会,就找了别人的题解学习了一下,然后又被线段树强大的力量给震撼到了。。
这种类似于分治的思想我一直不能很好的掌握。。。
题目大意就是给你一段序列每次查需(l,r)内最大的连续区间和。
对于一个区间的最大连续和它可能出现的位置,前缀 后缀 或者从中间向两边拓展
所以对于每一个节点我们维护他的
ls:从左端点开始的最大连续和
rs 以右端点结束的最大连续和
ms:整个区间的最大连续和
s:区间和。
至于为什么要维护一个区间和,其实也是为了转移方便。
对于一个父节点它的ls 能够更新位左子区间的和加上右子区间的ls。
下面说明如何合并两个区间。
ls :max (lson.ls,lson.s+rson.ls);
rs :max(rson.rs,rson.s+lson.rs);
ms:max( max(lson.ms,rson.ms),lson.rs+rson.ls);//这里是因为最大连续和可能出现在从中间到两边拓展的情况。
以上是合并两个区间。。
下面是如何查询。
如何合并区间容易想到。。可能我对于递归还不是太了解,解决了区间合并却不知道要如何去查询。
对于我们要查询的区间我们可以把它分为2种情况。
当前节点完全等于查询的区间,查询的区间位当前节点的子区间。
这样对一个查询区间,我们就可以在线段树上找到若干个完整的区间,。。
比如当前的序列长度是1-7
如图所示:如果我们查询2-6
我们就可以在树上找到2 3-4 5-6
同样的当我们找到2 3-4 这样两个相邻区间时我们也要像建树时那样合并两个区间成位一个新的区间。。。
就是这样。。。
这个博主讲的很好:https://blog.csdn.net/wu_tongtong/article/details/73385029
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<set>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define sca(x) scanf("%d",&x)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define inf 0x3f3f3f3f
#define LL long long
#define N 50005
#define inf 0x3f3f3f3f
struct node
{
int ls,rs,s,ms;
}t[N*4];
int a[N];
void pushup(int rt)
{
t[rt].ls=max(t[rt<<1].ls,t[rt<<1].s+t[rt<<1|1].ls);
t[rt].rs=max(t[rt<<1|1].rs,t[rt<<1|1].s+t[rt<<1].rs);
t[rt].ms=max(t[rt<<1].ms,t[rt<<1|1].ms);
t[rt].ms=max(t[rt].ms,t[rt<<1].rs+t[rt<<1|1].ls);
t[rt].s=t[rt<<1].s+t[rt<<1|1].s;
return ;
}
void build(int rt,int l,int r)
{
if(l==r)
{
t[rt].ls=a[l];
t[rt].rs=a[l];
t[rt].ms=a[l];
t[rt].s =a[l];
return ;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
pushup(rt);
}
node query(int rt,int l,int r,int ql,int qr)
{
if(l==ql && r==qr)
{
return t[rt];
}
int m=(l+r)>>1;
if(m>=qr)return query(rt<<1,l,m,ql,qr);
if(m<ql) return query(rt<<1|1,m+1,r,ql,qr);
else
{
node lans=query(rt<<1,l,m,ql,m);
node rans=query(rt<<1|1,m+1,r,m+1,qr);
node ans;
ans.ls=max(lans.ls,lans.s+rans.ls);
ans.rs=max(rans.rs,rans.s+lans.rs);
ans.ms=max(lans.ms,rans.ms);
ans.ms=max(ans.ms,lans.rs+rans.ls);
ans.s=lans.s+rans.s;
return ans;
}
}
int main()
{
int n;
sca(n);
rep(i,1,n)
{
sca(a[i]);
}
build(1,1,n);
int m;
sca(m);
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
node ans=query(1,1,n,l,r);
printf("%d\n",ans.ms);
}
}
/*
5
1 3 -2 4 2
3
1 3
2 4
3 5
*/
upc 一个带修改的题目
Can you answer on these queries III
时间限制: 1 Sec 内存限制: 128 MB
提交: 6 解决: 4
[提交] [状态] [讨论版] [命题人:admin]
题目描述
给定长度为N的数列A,以及M条指令 (N≤500000, M≤100000),每条指令可能是以下两种之一:
“2 x y”,把 A[x] 改成 y。
“1 x y”,查询区间 [x,y] 中的最大连续子段和,即 max(x≤l≤r≤y) { ∑(i=l~r) A[i] }。
对于每个询问,输出一个整数表示答案。
输入
第一行两个整数N,M
第二行N个整数Ai
接下来M行每行3个整数k,x,y,k=1表示查询(此时如果x>y,请交换x,y),k=2表示修改
输出
对于每个询问输出一个整数表示答案。
样例输入
5 3 1 2 -3 4 5 1 2 3 2 2 -1 1 3 2
样例输出
2 -1
提示
对于100%的数据: N≤500000, M≤100000, |Ai|<=1000
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<set>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define sca(x) scanf("%d",&x)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define inf 0x3f3f3f3f
#define LL long long
#define N 500005
#define inf 0x3f3f3f3f
struct node
{
int ls,rs,s,ms;
}t[N*4];
int a[N];
void pushup(int rt)
{
t[rt].ls=max(t[rt<<1].ls,t[rt<<1].s+t[rt<<1|1].ls);
t[rt].rs=max(t[rt<<1|1].rs,t[rt<<1|1].s+t[rt<<1].rs);
t[rt].ms=max(t[rt<<1].ms,t[rt<<1|1].ms);
t[rt].ms=max(t[rt].ms,t[rt<<1].rs+t[rt<<1|1].ls);
t[rt].s=t[rt<<1].s+t[rt<<1|1].s;
return ;
}
void build(int rt,int l,int r)
{
if(l==r)
{
t[rt].ls=a[l];
t[rt].rs=a[l];
t[rt].ms=a[l];
t[rt].s =a[l];
return ;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
pushup(rt);
}
node query(int rt,int l,int r,int ql,int qr)
{
if(l==ql && r==qr)
{
return t[rt];
}
int m=(l+r)>>1;
if(m>=qr)return query(rt<<1,l,m,ql,qr);
if(m<ql) return query(rt<<1|1,m+1,r,ql,qr);
else
{
node lans=query(rt<<1,l,m,ql,m);
node rans=query(rt<<1|1,m+1,r,m+1,qr);
node ans;
ans.ls=max(lans.ls,lans.s+rans.ls);
ans.rs=max(rans.rs,rans.s+lans.rs);
ans.ms=max(lans.ms,rans.ms);
ans.ms=max(ans.ms,lans.rs+rans.ls);
ans.s=lans.s+rans.s;
return ans;
}
}
void update(int rt,int l,int r,int pos,int k)
{
//cout<<l<<" "<<r<<endl;
if(l==r)
{
t[rt].ls=k;
t[rt].rs=k;
t[rt].ms=k;
t[rt].s =k;
return ;
}
int m=(l+r)>>1;
if(pos<=m)update(rt<<1,l,m,pos,k);
else update(rt<<1|1,m+1,r,pos,k);
pushup(rt);
}
int main()
{
int n,m;
sca(n);
sca(m);
rep(i,1,n)
{
sca(a[i]);
}
build(1,1,n);
while(m--)
{
int x,l,r;
scanf("%d%d%d",&x,&l,&r);
if(x==1)
{
if(l>r)swap(l,r);
node ans=query(1,1,n,l,r);
printf("%d\n",ans.ms);
}
else update(1,1,n,l,r);
}
}
/*
5
1 3 -2 4 2
3
1 3
2 4
3 5
*/