SP1043 GSS1 - Can you answer these queries I(猫树)

给出了序列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个查询,程序必须输出这些查询的结果。

这就是一个最大子段和,用线段树就能直接搞掉

然后这里学习了一下一个叫做猫树的神奇东西->这里

能做到预处理之后查询$O(1)$

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 using namespace std;
 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 6 char buf[1<<21],*p1=buf,*p2=buf;
 7 int read(){
 8     #define num ch-‘0‘
 9     char ch;bool flag=0;int res;
10     while(!isdigit(ch=getc()))
11     (ch==‘-‘)&&(flag=true);
12     for(res=num;isdigit(ch=getc());res=res*10+num);
13     (flag)&&(res=-res);
14     #undef num
15     return res;
16 }
17 char sr[1<<21],z[20];int C=-1,Z;
18 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
19 void print(int x){
20     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
21     while(z[++Z]=x%10+48,x/=10);
22     while(sr[++C]=z[Z],--Z);sr[++C]=‘\n‘;
23 }
24 const int N=5e+5;
25 int n,m,a[N],len,log[N],pos[N],p[21][N],s[21][N];
26 void build(int pp,int l,int r,int d){
27     if(l==r) return (void)(pos[l]=pp);
28     int mid=(l+r)>>1,prep,sm;
29     p[d][mid]=s[d][mid]=sm=prep=a[mid];
30     if(sm<0) sm=0;
31     for(int i=mid-1;i>=l;--i){
32         prep+=a[i],sm+=a[i];
33         s[d][i]=max(s[d][i+1],prep),
34         p[d][i]=max(p[d][i+1],sm);
35         if(sm<0) sm=0;
36     }
37     p[d][mid+1]=s[d][mid+1]=sm=prep=a[mid+1];
38     if(sm<0) sm=0;
39     for(int i=mid+2;i<=r;++i){
40         prep+=a[i],sm+=a[i];
41         s[d][i]=max(s[d][i-1],prep),
42         p[d][i]=max(p[d][i-1],sm);
43         if(sm<0) sm=0;
44     }
45     build(pp<<1,l,mid,d+1);
46     build(pp<<1|1,mid+1,r,d+1);
47 }
48 int query(int l,int r){
49     if(l==r) return a[l];
50     int d=log[pos[l]]-log[pos[l]^pos[r]];
51     return max(max(p[d][l],p[d][r]),s[d][l]+s[d][r]);
52 }
53 int main(){
54 //    freopen("testdata.in","r",stdin);
55     n=read();for(int i=1;i<=n;++i) a[i]=read();
56     len=2;while(len<n) len<<=1;
57     for(int i=2,l=len<<1;i<=l;++i) log[i]=log[i>>1]+1;
58     build(1,1,len,1);
59     m=read();
60     while(m--){
61         int l=read(),r=read();
62         print(query(l,r));
63     }
64     return Ot(),0;
65 }

原文地址:https://www.cnblogs.com/bztMinamoto/p/9826116.html

时间: 2024-08-30 18:24:31

SP1043 GSS1 - Can you answer these queries I(猫树)的相关文章

SP1043 GSS1 - Can you answer these queries I 线段树

问题描述 LG-SP1043 题解 GSS 系列第一题. \(q\) 个询问,求 \([x,y]\) 的最大字段和. 线段树,维护 \([x,y]\) 的 \(lmax,rmax,sum,val\) ,向上合并即可. 但是注意询问过程中也需要维护这些信息. \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace std; template <typename Tp> void read(Tp &x){ x=0;ch

[SP1043]GSS1 - Can you answer these queries I

求区间内最大非空子段和,没什么可说的吧. 线段树,每个区间维护从左端开始的最大非空子段和,区间内的最大非空子段和,以右端结束的最大非空子段和,还有区间和. pushup()的写法要注意,不要漏掉任何一种情况. 代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 using namespace std; 6 inline int re

SP1043 GSS1 - Can you answer these queries I(线段树,区间最大子段和(静态))

题目描述 给出了序列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个查询,程序必须输出这些查询的结果. 输入输出格式 输入格式: 输入文件的第一行包含整数N. 在第二行,N个数字跟随. 第三行包含整数M. M行跟在后面,其中第1行包含两个数字xi和yi. 输出格式: 您的程序应该输出M查询的结果,每一行一个查询. 思路: 我们做这道题首先应该想的,是两个

SP1716 GSS3 - Can you answer these queries III 线段树

题目传送门:SP1043 GSS1 - Can you answer these queries I 更好的阅读体验 动态维护子段和最大值 前置知识 静态维护子段和最大值:SP1043 GSS1 - Can you answer these queries I 题解传送 题解: 提供结构体指针线段树写法: 设\(l\)为区间左端点, \(r\)为区间右端点: \(ls\)为以\(l\)为左端点的最大子段和, \(rs\)为以\(r\)为右端点的最大子段和; \(sum\)为区间和, \(val\

hdu4027 Can you answer these queries?(线段树平方减少,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4027 Problem Description A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapon to eliminate the bat

SPOJ GSS3 Can you answer these queries III (线段树)

题目大意: 求区间最大子区间的和. 思路分析: 记录左最大,右最大,区间最大. 注意Q_L  和 Q_R  就好. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e #define maxn 55555 using na

SPOJ GSS4 Can you answer these queries IV (线段树)

题目大意: 给出N个数 0     操作   把 l -----  r之间的数全部开平方 1     操作  输出 l -----r  之间的和 思路分析: 判断区间里的数字是否全相同.如果相同, 将cov 置为该数 查询的时候和更新的时候,如果碰到cov != -1 的  就直接返回就可以了 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #incl

HDU 4027 Can you answer these queries?(线段树的单点更新+区间查询)

题目链接 题意 : 给你N个数,进行M次操作,0操作是将区间内的每一个数变成自己的平方根(整数),1操作是求区间和. 思路 :单点更新,区间查询,就是要注意在更新的时候要优化,要不然会超时,因为所有的数开几次方之后都会变成1,所以到了1不用没完没了的更新. 1 //HDU 4027 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <iostream> 6 #defi

SPOJ GSS1 Can you answer these queries I

Can you answer these queries I Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Original ID: GSS164-bit integer IO format: %lld      Java class name: Main You are given a sequence $A[1], A[2], ..., A[N] $. $( |A[i]| \leq