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

来源:互联网 发布:无印良品 推荐 知乎 编辑:程序博客网 时间:2024/04/29 03:27

题意:给你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[N];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[N];LL res[N];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;}


原创粉丝点击