UVALive - 3938 Ray, Pass methe dishes!"(动态最大连续和子序列,线段树区间合并)
2018-03-10 17:29
525 查看
题意: 给出一个长度为n的整数序列D,你的任务是对m各询问做出回答。对于询问(a,b),需要找到两个下标x和y,使得a<=x<=y<=b,并且Dx+Dx+1+...+Dy尽量大。如果有多组满足条件的x和y,x应该尽量小。如果还有多解,y应该尽量小。 题解: 蓝书上的线段树练习题,做起来感觉还是不简单地,比起来前面做过的那些题,这种区间合并,多重递归的要复杂的多! 建立一颗线段树,每个节点维护以下信息: max_sub : 本节点维护的最大连续和的子区间[L,R]max_prefix : 本节点的最大前缀和区间的右端坐标Rmax_suffix :本节点的最大后缀和区间的左端坐标L 举个栗子:对于一个查询[20,50] 区间的最大连续和,由于区间被分成了[20,32],[33,50],结果只有以下三种情况: 1. 最大连续和在[20,32]中,即max_sub[20,32]2. 最大连续和在[33,50]中,即max_sub[33,50]3. 最大连续和x在[20,32]中,y在[33,50]中。也就是max_sum[20,50]=max_suffix[20,32]+max_prefix[33,50],并且更新x,y的坐标。 难点就在于还要在递归的去求max_prefix,max_suffix。 #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
#include<vector>
#include<functional>
#include<utility>
#include<set>
#include<map>
#include<cmath>
#include<cctype>
#define INF 0x3f3f3f3f
using namespace std;
#define lson 2*i,l,m
#define rson 2*i+1,m+1,r
const int maxn=500000+100;
typedef pair<int,int>pii;
pii max_sub[maxn<<2];
int max_prefix[maxn<<2],max_suffix[maxn<<2];
long long prefix_sum[maxn];
//后面有两种调用方式。
long long get_sum(int l,int r)
{
return prefix_sum[r]-prefix_sum[l-1];
}
long long get_sum(pii p)
{
return get_sum(p.first,p.second);
}
pii better(pii a,pii b)
{
if(get_sum(a)!=get_sum(b))return get_sum(a)>get_sum(b)?a:b;
return a<b? a:b;
}
void pushup(int i,int l,int r)
{
//计算最大和
max_sub[i]=better(max_sub[2*i],max_sub[2*i+1]);//直接从左边或者右边
max_sub[i]=better(max_sub[i],pii(max_suffix[2*i],max_prefix[2*i+1]));//左半边和右半边都有
//计算前缀
long long x=get_sum(l,max_prefix[2*i]);//前缀和来自前半边
long long y=get_sum(l,max_prefix[2*i+1]);//前缀和的右端点在右半边
if(x==y)max_prefix[i]= max_prefix[2*i];//两者相等,取前半边
else max_prefix[i]=x>y?max_prefix[2*i]:max_prefix[2*i+1];
//计算后缀
x=get_sum(max_suffix[i*2],r);
y=get_sum(max_suffix[2*i+1],r);
if(x==y) max_suffix[i]=max_suffix[2*i];
else max_suffix[i]=x>y?max_suffix[2*i]:max_suffix[2*i+1];
}
void build(int i,int l,int r)
{
if(l==r)
{
max_sub[i]=pii(l,r);
max_prefix[i]=max_suffix[i]=l;
return;
}
int m=(l+r)/2;
build(lson);
build(rson);
pushup(i,l,r);
}
pii query_prefix(int ql,int qr,int i,int l,int r)
{
if(max_prefix[i]<=qr)return pii(l,max_prefix[i]);
int m=(l+r)/2;
if(qr<=m)return query_prefix(ql,qr,lson);//干脆地去找左半区间
pii a=query_prefix(ql,qr,rson);//找右半区间的最大前缀,此时区间左边不是l了。
a.first=l;
return better(a,pii(l,max_prefix[2*i]));//
}
pii query_suffix(int ql,int qr,int i,int l,int r)
{
if(max_suffix[i]>=ql)return pii(max_suffix[i],r);
int m=(l+r)/2;
if(m<ql)return query_suffix(ql,qr,rson);
pii a=query_suffix(ql,qr,lson);
a.second=r;
return better(a,pii(max_suffix[2*i+1],r));
}
pii query(int ql,int qr,int i,int l,int r)
{
if(ql<=l&&qr>=r)return max_sub[i];
int m=(l+r)/2;
if(qr<=m)return query(ql,qr,lson);
if(ql>m)return query(ql,qr,rson);
int L=query_suffix(ql,qr,lson).first;
int R=query_prefix(ql,qr,rson).second;
pii a=better(query(ql,qr,lson),query(ql,qr,rson));//单独来自左半边或者右半边
return better(pii(L,R),a);
}
int main()
{
int n,m;
int kase=1;
while(cin>>n>>m&&n&&m)
{
prefix_sum[0]=0;
for(int i=1; i<=n; i++)
{
int x;
scanf("%d",&x);
prefix_sum[i]=prefix_sum[i-1]+x;
}
build(1,1,n);
printf("Case %d:\n",kase++);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
pii a=query(x,y,1,1,n);
printf("%d %d\n",a.first,a.second);
}
}
}
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
#include<vector>
#include<functional>
#include<utility>
#include<set>
#include<map>
#include<cmath>
#include<cctype>
#define INF 0x3f3f3f3f
using namespace std;
#define lson 2*i,l,m
#define rson 2*i+1,m+1,r
const int maxn=500000+100;
typedef pair<int,int>pii;
pii max_sub[maxn<<2];
int max_prefix[maxn<<2],max_suffix[maxn<<2];
long long prefix_sum[maxn];
//后面有两种调用方式。
long long get_sum(int l,int r)
{
return prefix_sum[r]-prefix_sum[l-1];
}
long long get_sum(pii p)
{
return get_sum(p.first,p.second);
}
pii better(pii a,pii b)
{
if(get_sum(a)!=get_sum(b))return get_sum(a)>get_sum(b)?a:b;
return a<b? a:b;
}
void pushup(int i,int l,int r)
{
//计算最大和
max_sub[i]=better(max_sub[2*i],max_sub[2*i+1]);//直接从左边或者右边
max_sub[i]=better(max_sub[i],pii(max_suffix[2*i],max_prefix[2*i+1]));//左半边和右半边都有
//计算前缀
long long x=get_sum(l,max_prefix[2*i]);//前缀和来自前半边
long long y=get_sum(l,max_prefix[2*i+1]);//前缀和的右端点在右半边
if(x==y)max_prefix[i]= max_prefix[2*i];//两者相等,取前半边
else max_prefix[i]=x>y?max_prefix[2*i]:max_prefix[2*i+1];
//计算后缀
x=get_sum(max_suffix[i*2],r);
y=get_sum(max_suffix[2*i+1],r);
if(x==y) max_suffix[i]=max_suffix[2*i];
else max_suffix[i]=x>y?max_suffix[2*i]:max_suffix[2*i+1];
}
void build(int i,int l,int r)
{
if(l==r)
{
max_sub[i]=pii(l,r);
max_prefix[i]=max_suffix[i]=l;
return;
}
int m=(l+r)/2;
build(lson);
build(rson);
pushup(i,l,r);
}
pii query_prefix(int ql,int qr,int i,int l,int r)
{
if(max_prefix[i]<=qr)return pii(l,max_prefix[i]);
int m=(l+r)/2;
if(qr<=m)return query_prefix(ql,qr,lson);//干脆地去找左半区间
pii a=query_prefix(ql,qr,rson);//找右半区间的最大前缀,此时区间左边不是l了。
a.first=l;
return better(a,pii(l,max_prefix[2*i]));//
}
pii query_suffix(int ql,int qr,int i,int l,int r)
{
if(max_suffix[i]>=ql)return pii(max_suffix[i],r);
int m=(l+r)/2;
if(m<ql)return query_suffix(ql,qr,rson);
pii a=query_suffix(ql,qr,lson);
a.second=r;
return better(a,pii(max_suffix[2*i+1],r));
}
pii query(int ql,int qr,int i,int l,int r)
{
if(ql<=l&&qr>=r)return max_sub[i];
int m=(l+r)/2;
if(qr<=m)return query(ql,qr,lson);
if(ql>m)return query(ql,qr,rson);
int L=query_suffix(ql,qr,lson).first;
int R=query_prefix(ql,qr,rson).second;
pii a=better(query(ql,qr,lson),query(ql,qr,rson));//单独来自左半边或者右半边
return better(pii(L,R),a);
}
int main()
{
int n,m;
int kase=1;
while(cin>>n>>m&&n&&m)
{
prefix_sum[0]=0;
for(int i=1; i<=n; i++)
{
int x;
scanf("%d",&x);
prefix_sum[i]=prefix_sum[i-1]+x;
}
build(1,1,n);
printf("Case %d:\n",kase++);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
pii a=query(x,y,1,1,n);
printf("%d %d\n",a.first,a.second);
}
}
}
相关文章推荐
- UVALive3938 "Ray, Pass me the dishes!" 线段树动态区间最大和
- uvalive 3938 - "Ray, Pass me the dishes!" +动态最大连续和+线段树
- UVaLive 3938 "Ray, Pass me the dishes!" (线段树求动态最大连续和)
- UVA 1400 "Ray, Pass methe dishes!"(线段树,区间合并)
- UVALive3938 "Ray, Pass me the dishes!" 线段树动态区间最大和
- Uva 1400 "Ray, Pass me the dishes!" (线段树 区间合并)
- UVALive 3938 Ray, Pass me the dishes! (动态最大连续和)
- UVALive - 3938 "Ray, Pass me the dishes!" 线段树
- UVALive 3938 Ray, Pass me the dishes (线段树区间合并)
- UVa 1400 "Ray, Pass me the dishes!"(区间最大连续数组和)
- Regionals 2007 >> Asia - Nanjing - "Ray, Pass me the dishes!" 线段树 难 uva live 3938
- LA3938 "Ray, Pass me the dishes!" (线段树区间合并)
- UVA live 3938 - "Ray, Pass me the dishes!"(线段树)
- [线段树点修改]动态最大连续和(Ray,Pass me the Dishes, LA 3938)
- UVALive - 3938 "Ray, Pass me the dishes!"
- LA3938-Ray, Pass me the dishes!--动态最大连续区间和(线段树+前后缀数和组)
- UVA-1400-"Ray, Pass me the dishes!"(线段树-区间合并)
- uva 1400 Ray, Pass me the dishes!(线段树, 分治法求最大连续和)
- uva 1400 "Ray, Pass me the dishes!" 线段树
- LA 3938 "Ray, Pass me the dishes!" / 线段树单点更新