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)的了,相当于懒操作值没起作用。
离线处理查询。每个值只能计算一次的方法同之前的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; }
相关文章推荐
- [SPOJ1557][GSS2][线段树]Can you answer these queries II[好题]
- SPOJ 1557 Can you answer these queries II(GSS2 线段树)
- spoj 1557 Can you answer these queries II (gss2)线段树
- SPOJ GSS2 Can you answer these queries II
- bzoj 2482: [Spoj1557] Can you answer these queries II
- SPOJ GSS2 Can you answer these queries II
- Spoj 1557 Can you answer these queries II 线段树 随意区间最大子段和 不反复数字
- Spoj 1557 Can you answer these queries II 线段树 任意区间最大子段和 不重复数字
- 【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树
- 【SPOJ】1557 Can you answer these queries II
- SPOJ 1557. Can you answer these queries II 线段树
- bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树
- SPOJ 1557 Can you answer these queries II(离线处理+线段树求历史最大)
- SPOJ 1557 Can you answer these queries II(线段树)
- 【SPOJ】1557 Can you answer these queries II 线段树
- SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)
- SPOJ 1557. Can you answer these queries II (很强的线段树)
- SPOJ GSS2 Can you answer these queries II
- SPOJ GSS2 Can you answer these queries II ——线段树
- bzoj2482 [Spoj1557] Can you answer these queries II