zoukankan      html  css  js  c++  java
  • SPOJGSS3 Can you answer these queries III

    Description

      You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations: modify the i-th element in the sequence or for given x y print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.

    Input

      The first line of input contains an integer N. The following line contains N integers, representing the sequence A1..AN.
      The third line contains an integer M. The next M lines contain the operations in following form:
      0 x y: modify Ax into y (|y|<=10000).
      1 x y: print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.

    Output

      For each query, print an integer as the problem required.

    Solution

      如果没有修改操作,咋办办呢?我也不知道啊。其实有没有修改都是一个样的呢!
      考虑询问,发现对于一段询问的区间l,r,我们如果把它分成两段([l,mid])((mid,r])
       很容易发现所谓的区间最大连续子段和要么就是在([l,mid])中,要么就是在((mid,r])中,要么就是横跨mid,对于前两种情况,可以分治下去解决。
       对于第三种情况,你发现最终答案只会是形如(sum_{i=L}^R a_i (L<=mid<R) Rightarrow sum_{i=L}^{mid} a_i + sum_{i=mid+1}^R a_i)
       那么如何对区间进行拆分呢?对于区间问题,我们可以YY线段树,让线段树的每个节点记录该节点代表区间的最大子段和,从左端点开始的最大子段和,到右端点结束的最大子段和。
       那么询问,我们可以通过合并([l,r])所包含的区间来得到最终答案(具体过程详见up函数)
       其实单点修改很好写,这里也不多做解释,直接上代码

    Code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    struct node
    {
    	int mx,sum,lmx,rmx;
    }tre[200000];
    int n,a[50010],Q;
    void up(node &a,node b,node c)
    {
    	a.sum=b.sum+c.sum;
    	a.mx=max(b.mx,c.mx);
    	a.mx=max(a.mx,b.rmx+c.lmx);
    	a.lmx=max(b.lmx,b.sum+max(c.lmx,0));
    	a.rmx=max(c.rmx,c.sum+max(b.rmx,0));
    }
    void build(int p,int l,int r)
    {
    	if (l==r)
    	{
    		tre[p].sum=tre[p].mx=tre[p].lmx=tre[p].rmx=a[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(p<<1,l,mid);
    	build(p<<1|1,mid+1,r);
    	up(tre[p],tre[p<<1],tre[p<<1|1]);
    }
    void modify(int p,int l,int r,int pos,int key)
    {
    	if (l==r)
    	{
    		tre[p].sum=tre[p].lmx=tre[p].rmx=tre[p].mx=key;
    		return;
    	}
    	int mid=(l+r)>>1;
    	if (pos<=mid) modify(p<<1,l,mid,pos,key);
    	else modify(p<<1|1,mid+1,r,pos,key);
    	up(tre[p],tre[p<<1],tre[p<<1|1]);
    }
    node query(int p,int l,int r,int i,int j)
    {
    	if (l==i && r==j) return tre[p];
    	int mid=(l+r)>>1;
    	if (j<=mid) return query(p<<1,l,mid,i,j);
    	else if (i>mid) return query(p<<1|1,mid+1,r,i,j);
    	else
    	{
    		node ans;
    		up(ans,query(p<<1,l,mid,i,mid),query(p<<1|1,mid+1,r,mid+1,j));
    		return ans;
    	}
    }
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    	build(1,1,n);
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		int opt,x,y;
    		scanf("%d%d%d",&opt,&x,&y);
    		if (opt)
    		{
    			node ans=query(1,1,n,x,y);
    			printf("%d
    ",ans.mx);
    		}
    		else modify(1,1,n,x,y);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Golang语言编程规范
    关于redis的几件小事(三)redis的数据类型与使用场景
    关于redis的几件小事(二)redis线程模型
    关于redis的几件小事(一)redis的使用目的与问题
    关于MQ的几件小事(七)如果让你设计一个MQ,你怎么设计
    关于MQ的几件小事(六)消息积压在消息队列里怎么办
    关于MQ的几件小事(五)如何保证消息按顺序执行
    关于MQ的几件小事(四)如何保证消息不丢失
    关于MQ的几件小事(三)如何保证消息不重复消费
    关于MQ的几件小事(二)如何保证消息队列的高可用
  • 原文地址:https://www.cnblogs.com/Code-Geass/p/9791532.html
Copyright © 2011-2022 走看看