LA3938-Ray, Pass me the dishes!--动态最大连续区间和(线段树+前后缀数和组)
来源:互联网 发布:国际js舞蹈培训好不好 编辑:程序博客网 时间:2024/05/22 13:22
更新:之前的写法那么挫居然也过了。。。缝缝改改最后从1.4S改成700ms了。。。主要改的地方是两处 ,见注释
修改后的代码放在最后面(700ms)
最后重xie(400ms)
题意:给一个数组,求任意区间的最大连续和 长度n,查询次数m n,m大小是5*10^5
每个数不超过1e9
之前做的是静态数组求一次最大连续和,方法有很多,dp之类的都能o(n)解决。
还有一个是分治法,nlogn解决:http://blog.csdn.net/viphong/article/details/48221429
这里也是用分治法的思路解决:
称区间【l,r】的最大连续区间和为st_max[l,r]
对查询区间(a,b)
int mid=(a+b)/2;
要求st_max的话, 有三种情况:
情况1: st_max的起点和终点都在【a,mid】
情况2:st_max的起点和终点都在【mid+1,b】
情况3:st_max的起点在【a,mid】,终点在【mid+1,b】
对于情况三 : st_max= max_suffix(a,mid)+max_prefix(mid+1,b) 【容易理解】
其中max_suffix为一区间的最大后缀和
其中max_prefix为一区间的最大前缀和
所以,任意区间的st_max 都可求得。只要不断递归下去就可以了。 【线段树维护区间的结果】
而对于max_suffix、max_prefix,我们也是用分治的方法来求
例如 要求max_prefix【a,b】
那么先求max_prefix【a,mid】和max_prefix【mid+1,b】
然后选 max_prefix【a,mid】 和max_prefix【mid+1,b】+sum[mid] 中 较大的一个 即为 【a,b】的最大前缀和,其中sum【i】为前缀和数组
同理也可以分治求得max_suffix
-------------------------------------------------
最终是 用 两个线段树分别维护 max_prefix、max_suffix
再用一棵线段树维护最大连续和
建树nlogn
每次查询logn...常数应该比较大....所以跑了1.4S。。。犇都是0.x秒
1、要注意的是inf不能设为2^63-1 会溢出
2、维护某个最大连续和对应的始末位置 我是另创了一个node来记录
3、在情况三下,用query_max查找最大前/后缀和的时候,
查询的l,应该是当前区间的l和要查询的区间的l中 较大的一个
查询的r,应该是当前区间的r和要查询的区间的r中 较小的一个
重写了一次代码。。
#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <queue>#include <map>#include <set>#include <vector>#define lson l , m , i << 1#define rson m + 1 , r , i << 1 | 1using namespace std;typedef long long ll;const ll inf=1223372036854775807;struct node{ ll v,l,r; node() {} node(ll a,ll b,ll c) { v=a,l=b,r=c; } bool operator<(const node b) const { if (v!=b.v) return v<b.v; if (l!=b.l) return l>b.l; return r>b.r; }};const int N = 500005+50;ll aa[N];ll psum[N],ok;node sub[4*N],pre[4*N],suf[4*N];void push_pre(int i,int l,int r){ int mid=(l+r)>>1; node r1(psum[mid]-psum[l-1]+pre[i<<1|1].v,l,pre[i<<1|1].r); pre[i]= max(r1,pre[i<<1]);}void push_suf(int i,int l,int r){ int mid=(l+r)>>1; node r1(psum[r]-psum[mid]+suf[i<<1].v,suf[i<<1].l,r); suf[i]= max(r1,suf[i<<1|1]);}void pushup_ans(int i,int l,int r){ node r1(suf[i<<1].v+pre[i<<1|1].v,suf[i<<1].l,pre[i<<1|1].r); r1=max(r1,sub[i<<1]); sub[i]= max(r1,sub[i<<1|1]);}void build(int l,int r,int i) // 线段树的建立;{ if(l==r) { sub[i].l=pre[i].l=suf[i].l=l; sub[i].r=pre[i].r=suf[i].r=r; sub[i].v=pre[i].v=suf[i].v=aa[++ok]; return ; } int mid=(l+r)>>1; build(l,mid,i<<1); build(mid+1,r,i<<1|1); push_pre(i,l,r); push_suf(i,l,r); pushup_ans(i,l,r);}node query_pre(int qL,int qR,int l,int r,int i){ if (qL <= l && r <= qR) return pre[i]; int m = (l + r) >> 1; node ret1(-inf,l,m),ret2(-inf,m+1,r); if (qR <= m) return query_pre(qL , qR , lson); if (qL > m) return query_pre(qL , qR , rson); ret1 = query_pre(qL , qR , lson),ret2 = query_pre(qL , qR , rson); int LL=max(qL,l),RR=min(qR,r); node r1(psum[m]-psum[LL-1]+ret2.v,LL,ret2.r); return max(ret1,r1);}node query_suf(int qL,int qR,int l,int r,int i){ if (qL <= l && r <= qR) return suf[i]; int m = (l + r) >> 1; node ret1(-inf,l,m),ret2(-inf,m+1,r); if (qR <= m) return query_suf(qL , qR , lson); if (qL > m) return query_suf(qL , qR , rson); ret1 = query_suf(qL , qR , lson),ret2 = query_suf(qL , qR , rson); int LL=max(qL,l),RR=min(qR,r); node r1(psum[RR]-psum[m]+ret1.v,ret1.l,RR); return max(ret2,r1);}node query_max(int qL,int qR,int l,int r,int i) //L,R为为查询区间,lr当前区间{ if (qL <= l && r <= qR) return sub[i]; int m = (l + r) >> 1; node ret1(-inf,l,m),ret2(-inf,m+1,r); if (qR <= m) return query_max(qL , qR , lson); if (qL > m) return query_max(qL , qR , rson); ret1= query_max(qL , qR , lson),ret2= query_max(qL , qR , rson); node p1=query_pre(qL , qR , rson); node s1=query_suf(qL , qR , lson); node ret(p1.v+s1.v,s1.l,p1.r); return max(ret,max(ret1,ret2));}int main(){ //freopen("in.txt","r",stdin); //freopen("out1.txt","w",stdout); int cnt=1; ll n ,a,b,i,m; while(scanf("%lld%lld", &n,&m)!=EOF) { for( i = 1; i <= n; i++) { scanf("%lld",&aa[i]); psum[i]=aa[i]+psum[i-1]; } // for( i = 1; i <= n; i++) // update(1,1,n,i,i,psum[i]); ok=0; build(1,n,1); int l,r; printf("Case %d:\n",cnt++); for (int i=1; i<=m; i++) { scanf("%d%d",&l,&r); node ans=query_max(l,r,1,n,1); printf("%lld %lld\n",ans.l,ans.r); } } return 0;}
- LA3938-Ray, Pass me the dishes!--动态最大连续区间和(线段树+前后缀数和组)
- LA3938 RAY, Pass me the dishes (动态最大连续和)
- [线段树点修改]动态最大连续和(Ray,Pass me the Dishes, LA 3938)
- UVaLive 3938 "Ray, Pass me the dishes!" (线段树求动态最大连续和)
- LA3938 "Ray, Pass me the dishes!" (线段树区间合并)
- uvalive 3938 - "Ray, Pass me the dishes!" +动态最大连续和+线段树
- UVALive3938 "Ray, Pass me the dishes!" 线段树动态区间最大和
- LA3938 & UVA1400 - Ray, Pass me the dishes!(线段树)
- LA3938:"Ray, Pass me the dishes!"(线段树)
- uva 1400 Ray, Pass me the dishes!(线段树, 分治法求最大连续和)
- UVa 1400"Ray, Pass me the dishes!"(区间最大连续数组和)
- UVa Ray, Pass me the dishes! (线段树)
- UVA 1400 "Ray, Pass me the dishes!" (线段树)
- UVALive - 3938 "Ray, Pass me the dishes!" (线段树)
- uvalive 3938 Ray, Pass me the dishes!(线段树)
- UVALive 3938 Ray, Pass me the dishes (线段树区间合并)
- LA3938 线段树 动态求区间最大连续和
- UVA-1400 Ray, Pass me the Dishes, LA 3938 , 线段树,区间查询
- uvalive5096(积分题)
- Android 控件之十一:RatingBar评分条
- NBUT 1218 You are my brother
- 如何用JQuery弹出小窗口(是注册页面)提交表单form
- 找到一个重复元素 - 面试题
- LA3938-Ray, Pass me the dishes!--动态最大连续区间和(线段树+前后缀数和组)
- NBUT 1220 SPY
- C语言
- Android 控件之十一:列表组件 ListView
- POJ-1477
- 安卓学习资料(强大)必看!!!
- android---listview
- C语言
- 浙江大学PAT_乙级_1015. 德才论 (25)