UVALive - 3938:"Ray, Pass me the dishes!"

优美的线段树

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MAXN 500000+10
#define ll long long
#define pii pair<int,int>
#define mp make_pair
using namespace std;
int a[MAXN];
int n,m;
struct Node{
    int pre_dat;
    ll pre_sum;
    int suf_dat;
    ll suf_sum;
    pii dat;
    ll sum;
    ll d;
    Node(int p1=0,ll p2=0,int p3=0,ll p4=0,pii p5=mp(0,0),ll p6=0,ll p7=0){
        pre_dat=p1,pre_sum=p2,suf_dat=p3,suf_sum=p4,dat=p5,sum=p6,d=p7;
    }
}data[MAXN<<2];
Node Merge(Node t1,Node t2){
    if(t1.dat==mp(0,0))return t2;
    if(t2.dat==mp(0,0))return t1;
    Node ret;
    ret.d=t1.d+t2.d;
    ret.pre_dat=t1.pre_dat,ret.pre_sum=t1.pre_sum;
    if(ret.pre_sum<t1.d+t2.pre_sum){
        ret.pre_dat=t2.pre_dat,ret.pre_sum=t1.d+t2.pre_sum;
    }
    ret.suf_dat=t2.suf_dat,ret.suf_sum=t2.suf_sum;
    if(ret.suf_sum<=t2.d+t1.suf_sum){
        ret.suf_dat=t1.suf_dat,ret.suf_sum=t2.d+t1.suf_sum;
    }
    ret.dat=t1.dat,ret.sum=t1.sum;
    if(ret.sum<t2.sum){
        ret.dat=t2.dat,ret.sum=t2.sum;
    }
    if(ret.sum<(t1.suf_sum+t2.pre_sum)||ret.sum==(t1.suf_sum+t2.pre_sum)&&ret.dat>mp(t1.suf_dat,t2.pre_dat)){
        ret.dat=mp(t1.suf_dat,t2.pre_dat),
        ret.sum=(t1.suf_sum+t2.pre_sum);
    }
    return ret;
}
void build(int k,int L,int R){
    if(L+1==R){
        data[k].pre_dat=data[k].suf_dat=L;
        data[k].dat=mp(L,L);
        data[k].d=data[k].pre_sum=data[k].suf_sum=data[k].sum=a[L];
        return;
    }
    build(k<<1,L,(L+R)>>1);
    build(k<<1|1,(L+R)>>1,R);
    data[k]=Merge(data[k<<1],data[k<<1|1]);
}
Node query(int a,int b,int k,int L,int R){
    if(b<=L||R<=a){
        return Node(0,0,0,0,mp(0,0),0,0);
    }
    else if(a<=L&&R<=b){
        return data[k];
    }
    else{
        int mid=((L+R)>>1);
        Node lc=query(a,b,k<<1,L,mid);
        Node rc=query(a,b,k<<1|1,mid,R);
        return Merge(lc,rc);
    }
}
void solve(){
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    build(1,1,n+1);
    while(m--){
        int x,y;
        scanf("%d%d",&x,&y);
        Node ans=query(x,y+1,1,1,n+1);
        printf("%d %d\n",ans.dat.first,ans.dat.second);
    }
}
int main()
{
//    freopen("data.in","r",stdin);
//    freopen("my.out","w",stdout);
    int T=0;
    while(~scanf("%d%d",&n,&m)){
        printf("Case %d:\n",++T);
        solve();
    }
    return 0;
}    
时间: 2024-10-14 23:59:02

UVALive - 3938:"Ray, Pass me the dishes!"的相关文章

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

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 - &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

&quot;Ray, Pass me the dishes!&quot;

uvaLive3938:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1939 题意:给你n个数,然后给你一个区间,让你查询这个区间内最大和连续子区间. 题解:哎.智商是硬伤啊,虽然线段树也做过不少题目,但是遇到这样的题目还是不会处理啊,看了别人的代码才明白了怎么做.用那个线段树维护区间最大前缀,最大后缀,以及真正的最大区间

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!

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

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这里也可以只维护两个域,再最后再考虑跨区间的问题这里没有