• GSS问题(一)


    GSS问题(一)

    又是喜闻乐见线段树内容辣!

    GSS问题是一类以线段树为基础的有趣的问题

    实际上这算是线段树的实际应用之一、但由于它实在经典又基础,所以实际上只是个模板题.

    题面:

    给出了序列 (A[1],A[2],…,A[N])((a[i]≤15007,1≤N≤50000))。查询定义如下:

    查询 ((x,y)=max{a[i]+a[i+1]+...+a[j];x≤i≤j≤y})。 给定M个查询,程序必须输出这些查询的结果。

    解释及思路

    给出特定区间,让你求出其中连续一段数组之和最大是多少,如果全是正数那显然太脑残了,如果有负数就稍微难办些,正负夹杂就几乎停止思考.

    但是我们曾接触过"最大子段和",一道经典的DP题,可不可以用DP来做?

    DP的复杂度是(O(n)),是比较优的解法,但是我们本题有多次查询,并且每次查询的区间并不一定相同

    这样一来复杂度最劣就成了(O(nm)),本题是过不了的,毕竟不可能只有1000次查询

    开头即提到,本题是线段树板子题,考虑如何充分利用上线段树的特性

    以下内容假设你知道线段树

    重点

    我们知道,线段树最为标志的结构特征就是节点多而有序,总可以代表那些不好表示的区间

    同时,我们可以在这些节点上记录信息,完成区间信息的维护

    对于这种"连续区间问题",我们该如何通过节点来完成维护呢

    显然,每个答案区间,大概率都是由不少的节点合并而来的,

    那么我们考虑,每个节点不光记录节点内的最大子段和,也记录节点左边连续最大的子段和,以及右边的.

    这样一来,在进行合并的时候,将相邻两个节点的各自一端的信息进行合并就可以了

    结合代码来看

    代码:

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define ci const int &
    using namespace std;
    const int N=500005;
    int n,m;
    ll a[N];
    struct node{
    	ll l,r,maxn,sum;
    	node(){
    		l=r=maxn=sum=0;
    	}
    }nd[N<<2];
    inline void build(ci k,ci l,ci r){
    	if(l==r){
    		nd[k].l=nd[k].r=nd[k].maxn=nd[k].sum=a[l];
    		return ;
    	}int mid=l+r>>1;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    	nd[k].sum=nd[k<<1].sum+nd[k<<1|1].sum;
    	nd[k].l=nd[k<<1].l;
    	nd[k].l=max(nd[k<<1].l,nd[k<<1].sum+nd[k<<1|1].l);
    	nd[k].r=nd[k<<1|1].r;
    	nd[k].r=max(nd[k<<1|1].r,nd[k<<1|1].sum+nd[k<<1].r);
    	nd[k].maxn=max(max(nd[k<<1].maxn,nd[k<<1|1].maxn),nd[k<<1].r+nd[k<<1|1].l);
    }
    inline node query(ci k,ci l,ci r,ci x,ci y){
    	if(x<=l&&r<=y) return nd[k];
    	int mid=l+r>>1;
    	node ret,le,ri;
    	if(x<=mid) le=query(k<<1,l,mid,x,y);
    	if(mid<y) ri=query(k<<1|1,mid+1,r,x,y);
    	ret.sum=le.sum+ri.sum;
    	if(x<=mid){
    		ret.l=le.l;
    		ret.l=max(le.l,le.sum+ri.l);	
    	}
    	else ret.l=ri.l;
    	if(mid<y){
    		ret.r=ri.r;
    		ret.r=max(ri.r,ri.sum+le.r);	
    	}else ret.r=le.r;
    	if(x<=mid&&mid<y)
    		ret.maxn=max(max(le.maxn,ri.maxn),le.r+ri.l);
    	else if(x<=mid)
    		ret.maxn=le.maxn;
    	else
    		ret.maxn=ri.maxn;
    	return ret;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&a[i]);
    	build(1,1,n);
    	scanf("%d",&m);
    	while(m--){
    		int l,r;
    		scanf("%d%d",&l,&r);
    		node ans=query(1,1,n,l,r);
    		printf("%lld
    ",ans.maxn);
    	}return 0;
    }
    
  • 相关阅读:
    JVM内存逃逸
    SQL中游标的使用
    配置JAVA环境变量中CLASSPATH变量的作用
    什么是单点登录?单点登录的三种实现方式
    oracle中 connect by prior 递归算法
    test
    mac idea 常见错误记录
    mac 常用操作命令记录
    mac idea 常用快捷键记录
    运行maven install命令时出现错误(BUILD FAILURE)
  • 原文地址:https://www.cnblogs.com/648-233/p/12774985.html
Copyright © 2020-2023  润新知