"Ray, Pass me the dishes!"

uvaLive3938:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1939

题意:给你n个数,然后给你一个区间,让你查询这个区间内最大和连续子区间。

题解:哎。智商是硬伤啊,虽然线段树也做过不少题目,但是遇到这样的题目还是不会处理啊,看了别人的代码才明白了怎么做。用那个线段树维护区间最大前缀,最大后缀,以及真正的最大区间。要注意父节点这三个变量是怎么由子节点推导出来的。还是贴代码吧。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int N=500009;
  7 int ll[N*3],rr[N*3];
  8 struct  Node{
  9    int pre,suf;
 10    int vx,vy;
 11 }num[N*3];
 12 long long sum[N];
 13 void pushup(int rt,int l,int r){
 14     if(sum[num[rt<<1].pre]-sum[l-1]>=sum[num[rt<<1|1].pre]-sum[l-1])
 15         num[rt].pre=num[rt<<1].pre;
 16     else
 17         num[rt].pre=num[rt<<1|1].pre;
 18     if(sum[r]-sum[num[rt<<1].suf-1]>=sum[r]-sum[num[rt<<1|1].suf-1])
 19         num[rt].suf=num[rt<<1].suf;
 20     else
 21         num[rt].suf=num[rt<<1|1].suf;
 22     long long v1=sum[num[rt<<1].vy]-sum[num[rt<<1].vx-1];
 23     long long v2=sum[num[rt<<1|1].vy]-sum[num[rt<<1|1].vx-1];
 24     long long v0=sum[num[rt<<1|1].pre]-sum[num[rt<<1].suf-1];
 25     if(v1>=v2){
 26         num[rt].vx=num[rt<<1].vx;
 27         num[rt].vy=num[rt<<1].vy;
 28     }
 29     else{
 30         num[rt].vx=num[rt<<1|1].vx;
 31         num[rt].vy=num[rt<<1|1].vy;
 32     }
 33     if(v0==sum[num[rt].vy]-sum[num[rt].vx-1]){
 34         if(num[rt<<1].suf<num[rt].vx){
 35         num[rt].vx=num[rt<<1].suf;
 36         num[rt].vy=num[rt<<1|1].pre;
 37         }
 38     }
 39      if(v0>sum[num[rt].vy]-sum[num[rt].vx-1]){
 40          num[rt].vx=num[rt<<1].suf;
 41         num[rt].vy=num[rt<<1|1].pre;
 42     }
 43 }
 44 void build(int rt,int l,int r){
 45      ll[rt]=l;
 46      rr[rt]=r;
 47      if(l==r){
 48         num[rt].pre=num[rt].suf=num[rt].vx=num[rt].vy=l;
 49         return;
 50      }
 51     int mid=(l+r)/2;
 52     build(rt<<1,l,mid);
 53     build(rt<<1|1,mid+1,r);
 54     pushup(rt,l,r);
 55 }
 56 Node query(int rt,int s,int t){
 57     if(ll[rt]==s&&rr[rt]==t)
 58         return num[rt];
 59      int mid=(ll[rt]+rr[rt])/2;
 60     if(mid>=t)return query(rt<<1,s,t);
 61     else if(mid<s)return query(rt<<1|1,s,t);
 62     else{
 63          Node temp1=query(rt<<1,s,mid);
 64          Node temp2=query(rt<<1|1,mid+1,t);
 65          Node temp;
 66     if(sum[temp1.pre]-sum[s-1]>=sum[temp2.pre]-sum[s-1])
 67         temp.pre=temp1.pre;
 68     else
 69        temp.pre=temp2.pre;
 70     if(sum[t]-sum[temp1.suf-1]>=sum[t]-sum[temp2.suf-1])
 71         temp.suf=temp1.suf;
 72     else
 73          temp.suf=temp2.suf;
 74     long long v1=sum[temp1.vy]-sum[temp1.vx-1];
 75     long long v2=sum[temp2.vy]-sum[temp2.vx-1];
 76     long long v0=sum[temp2.pre]-sum[temp1.suf-1];
 77     if(v1>=v2){
 78        temp.vx=temp1.vx;
 79        temp.vy=temp1.vy;
 80     }
 81     else{
 82          temp.vx=temp2.vx;
 83          temp.vy=temp2.vy;
 84     }
 85     if(v0==sum[temp.vy]-sum[temp.vx-1]){
 86         if(temp1.suf<temp.vx){
 87         temp.vx=temp1.suf;
 88         temp.vy=temp2.pre;
 89         }
 90     }
 91      if(v0>sum[temp.vy]-sum[temp.vx-1]){
 92         temp.vx=temp1.suf;
 93         temp.vy=temp2.pre;
 94     }
 95     return temp;
 96   }
 97 }
 98 int main(){
 99     int  cas=0,n,m,l,r;
100     long long tp;
101     while(~scanf("%d%d",&n,&m)){
102           memset(sum,0,sizeof(sum));
103         for(int i=1;i<=n;i++){
104             scanf("%lld",&tp);
105             sum[i]=sum[i-1]+tp;
106         }
107          build(1,1,n);
108         printf("Case %d:\n",++cas);
109         for(int i=1;i<=m;i++){
110             scanf("%d%d",&l,&r);
111             Node ans=query(1,l,r);
112             printf("%d %d\n",ans.vx,ans.vy);
113         }
114     }
115
116 }

"Ray, Pass me the dishes!",布布扣,bubuko.com

时间: 2024-12-20 21:00:09

"Ray, Pass me the dishes!"的相关文章

uva 1400 - &quot;Ray, Pass me the dishes!&quot;(线段树)

题目链接:uva 1400 - "Ray, Pass me the dishes!" 题目大意:给定一个长度为n个整数序列,对m次询问作出回答,对于每次询问(a,b),找到两个下标x,y使得x到y的连续和为区间a,b中最大的连续和,如果存在多解优先x小,然后y小. 解题思路:线段树,对于每个节点维护三个线段值: max_sub:区间连续最大和 max_prefix:区间连续前缀最大和 max_suffix:区间连续后缀最大和 建树的过程维护三个值,查询时只需考虑左右子节点的max_su

Uva 1400 &quot;Ray, Pass me the dishes!&quot; ( 线段树 + 区间查询 )

Uva  1400 "Ray, Pass me the dishes!" (线段树 + 区间查询) 题意: 给顶一个长度为n的整数序列D,我们的任务是对m的询问做出回答对于询问(a,b),需要找到两个下标x和y,是的 a <= x <= y <=b并且Dx+...........Dy 尽量大. x,y尽量小 分析: 这题是做线段树比较好的一题,大白书上介绍的是维护了三个域,maxsub,maxpre,maxsuf这里也可以只维护两个域,再最后再考虑跨区间的问题这里没有

UVAlive - 3938 —— &quot;Ray, Pass me the dishes!&quot; 【线段树】

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=22105 #include <iostream> #include <cstdio> #include <cstring> #include <string> #define INF 0x3f3f3f3f #define lson rt<<1, l, m #define rson rt<<1|1, m+1, r u

UVALive3938 &quot;Ray, Pass me the dishes!&quot; 线段树动态区间最大和

AC得相当辛苦的一道题,似乎不难,但是需要想仔细, 开始的时候的错误思路----是受之前做过的区间最长连续子串影响http://blog.csdn.net/u011026968/article/details/38357157 区间合并的时候,我直接按照---如果(左子树的最大前缀和长度==左子树的长度 && 右子树的前缀和>0),就合并左前缀,这想法有两个错误:1.右子树的前缀和==0的时候是不是要合并区间呢?题目要求x尽量小,如果x相同y尽量小(x是ans的区间左端点,y是Ans

UVA 1400 1400 - &amp;quot;Ray, Pass me the dishes!&amp;quot;(线段树)

UVA 1400 - "Ray, Pass me the dishes!" 题目链接 题意:给定一个序列,每次询问一个[L,R]区间.求出这个区间的最大连续子序列和 思路:线段树,每一个节点维护3个值.最大连续子序列.最大连续前缀序列,最大连续后缀序列,那么每次pushup的时候,依据这3个序列去拼凑得到新的一个结点就可以 代码: #include <cstdio> #include <cstring> #include <algorithm> us

UVA 1400 1400 - &quot;Ray, Pass me the dishes!&quot;(线段树)

UVA 1400 - "Ray, Pass me the dishes!" 题目链接 题意:给定一个序列,每次询问一个[L,R]区间,求出这个区间的最大连续子序列和 思路:线段树,每个节点维护3个值,最大连续子序列,最大连续前缀序列,最大连续后缀序列,那么每次pushup的时候,根据这3个序列去拼凑得到新的一个结点即可 代码: #include <cstdio> #include <cstring> #include <algorithm> usin

UVA-1400 Ray, Pass me the Dishes, LA 3938 , 线段树,区间查询

题意:给出一列数(n个),m次查询区间[l,r]的最大连续区间[x,y](l<=x<=y<=r).(n,m<=500 000) 思路:动态查询区间最大连续区间: 如果是求最大连续区间和: 用线段树维护最大连续和sum_sub.最大前缀和sum_prefix.最大后缀和sum_suffix. root.sum_sub = max{l.sum_sub, r.sum_sub, (l.sum_suffix + r.sum_prefix) }; 题目要求区间,类似的: 用线段树维护最大连续区

UVA-1400 Ray, Pass me the dishes!

UVA-1400 Ray, Pass me the dishes! 题意:给出一个长度为n的整数序列D,有m个询问,每个询问(a,b)找到两个下标x和y,使得a<=x<=y<=n,并且Dx+...+Dy尽量大.如果有多组满足条件的x和y,x应该尽量小.如果还有多解,y应该尽量小. 思路:线段树,对于一个区间,需要维护的值是这个区间的最大连续前缀和,后缀和以及最大连续和的数字下标出现位置.这样,当找(a,b)的最大连续和的下标位置时,分三种情况: 1:最大连续和的起点和终点都在[a,mid

LA3938:&quot;Ray, Pass me the dishes!&quot;(线段树)

Description After doing Ray a great favor to collect sticks for Ray, Poor Neal becomes very hungry. In return for Neal's help, Ray makes a great dinner for Neal. When it is time for dinner, Ray arranges all the dishes he makes in a single line (actua