您的位置:首页 > 产品设计 > UI/UE

spojGSS2 1557 Can you answer these queries II(成段更新)

2012-12-20 03:04 495 查看
题意:给你N个数,每个数a[i]的范围在[-100000,100000],然后有Q个查询,每个查询问区间[x,y]内最大子区间和为多少,并且重复出现的值只能计算一次(如果是负数,输出0,即可以子区间可以为空)。

离线处理查询。每个值只能计算一次的方法同之前的hdu 3333 Turing Tree & hdu 3874 Necklace (成段更新)及Codeforces Round #136 (Div. 2) D. Little Elephant and Array方法一样,不再赘述——解题报告Here

首先,因为是离线处理,我们是从左到右处理每个a[i]的,这题线段树的每个叶子结点里存储的是,位置1,2,...,i-1,i到当前位置i的区间和sum,及最大子区间和mx。明白了这点,那么问题是如何去维护最大子区间和mx。方法是通过sum,及两个懒操作值,flag_sum和flag_mx(分别表示在更新过程中这个区间的左右子儿子区间需要加上的值,设这个值为valu,并且从flag_sum=0加到flag_sum=valu的过程中,最大值是多少——flag_mx。

其次,mx,sum,flag_mx,flag_sum的初值都应该是0(因为,子区间可以为空,即应该排除负数)。向下传递两个懒操作值的方法是:子区间的flag_mx值为,其原值、子区间的flag_sum加上当前区间的flag_mx,中取一个较大值。之后,子区间的flag_sum加上当前区间的flag_sum。

为什么这么做呢?子区间的flag_mx的最大值,除了原值,还有可能出现在,子区间的flag_sum加到子区间的flag_sum加上当前区间的flag_sum的过程中,而这个过程中的最大值显然是子区间的flag_sum加上当前区间的flag_mx。

最后如何更新mx和sum呢?

对于非叶子结点:

当前区间的sum,从子区间的sum值中取较大值,再加上当前区间的flag_sum。

当前区间的mx,1.从子区间的mx值中取较大值。2.两个子区间的sum中取较大值,

再加上当前区间的flag_mx。

对于叶子结点:

当前区间的sum值即是flag_sum,mx即是flag_mx。

为什么这么做呢?

起先想能不能用直接用当前区间变化后的flag_sum、flag_mx去更新当前区间的sum、mx。后来发现有一个问题——如果这样做,那么每次变化都要向下传递这两个懒操作值。复杂度就退化成O(N)的了,相当于懒操作值没起作用。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define MID(a,b) (a+((b-a)>>1))
typedef long long LL;
const int N=100005;

struct OP
{
int st,ed,id;
OP(){}
OP(int a,int b,int c){st=a;ed=b;id=c;}
bool operator<(const OP &b)const
{ return ed<b.ed; }
}op
;
struct node
{
int lft,rht;
LL mx,sum;
LL flag_mx,flag_sum;
int mid(){return MID(lft,rht);}
void init() { mx=sum=flag_mx=flag_sum=0; }
void fun(LL a,LL b)
{
flag_mx=max(flag_mx,flag_sum+b);
flag_sum+=a;
}
};

int n,m,pos[N*2],a
;
LL res
;

struct Segtree
{
node tree[N*4];
void PushUp(int ind)
{
if(tree[ind].lft!=tree[ind].rht)
{
tree[ind].sum=max(tree[LL(ind)].sum,tree[RR(ind)].sum)+tree[ind].flag_sum;
tree[ind].mx=max(tree[LL(ind)].mx,tree[RR(ind)].mx);
tree[ind].mx=max(tree[ind].mx,
max(tree[LL(ind)].sum,tree[RR(ind)].sum)+tree[ind].flag_mx);
}
else
{
tree[ind].sum=tree[ind].flag_sum;
tree[ind].mx=tree[ind].flag_mx;
}
}
void PushDown(int ind)
{
LL &tmp1=tree[ind].flag_sum,&tmp2=tree[ind].flag_mx;
tree[LL(ind)].fun(tmp1,tmp2); PushUp(LL(ind));
tree[RR(ind)].fun(tmp1,tmp2); PushUp(RR(ind));
tmp1=tmp2=0;
}
void build(int lft,int rht,int ind)
{
tree[ind].lft=lft;	tree[ind].rht=rht;
tree[ind].init();
if(lft!=rht)
{
int mid=tree[ind].mid();
build(lft,mid,LL(ind));
build(mid+1,rht,RR(ind));
}
}
void updata(int st,int ed,int ind,int valu)
{
int lft=tree[ind].lft,rht=tree[ind].rht;
if(st<=lft&&rht<=ed)
{
tree[ind].fun(valu,valu);
PushUp(ind);
}
else
{
PushDown(ind);
int mid=tree[ind].mid();
if(st<=mid) updata(st,ed,LL(ind),valu);
if(ed >mid) updata(st,ed,RR(ind),valu);
PushUp(ind);
}
}
LL query(int st,int ed,int ind)
{
int lft=tree[ind].lft,rht=tree[ind].rht;
if(st<=lft&&rht<=ed) return tree[ind].mx;
else
{
PushDown(ind);
int mid=tree[ind].mid();
LL mx1=0,mx2=0;
if(st<=mid) mx1=query(st,ed,LL(ind));
if(ed> mid) mx2=query(st,ed,RR(ind));
//PushUp(ind);		//查询未更新值,这里可以不用向上传递
return max(mx1,mx2);
}
}
}seg;
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(pos,0,sizeof(pos));
for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=0;i<m;i++)
{
int st,ed;
scanf("%d%d",&st,&ed);
op[i]=OP(st,ed,i);
}
sort(op,op+m);

int ind=0;
seg.build(1,n,1);
for(int i=1;i<=n;i++)
{
int &tmp=pos[a[i]+N];
seg.updata(tmp+1,i,1,a[i]);
tmp=i;
while(ind<m&&op[ind].ed==i)
{
res[op[ind].id]=seg.query(op[ind].st,op[ind].ed,1);
ind++;
}
}
for(int i=0;i<m;i++) printf("%lld\n",res[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: