当前位置: 代码迷 >> 综合 >> UVA 1400 Ray, Pass methe dishes!(线段树,区间合并)
  详细解决方案

UVA 1400 Ray, Pass methe dishes!(线段树,区间合并)

热度:94   发布时间:2024-01-15 06:43:28.0

UVA 1400 - "Ray, Pass me the dishes!"
 

题意:

       给出一个长度为n的整数序列D,你的任务是对m各询问做出回答。对于询问(a,b),需要找到两个下标x和y,使得a<=x<=y<=b,并且Dx+Dx+1+...+Dy尽量大。如果有多组满足条件的x和y,x应该尽量小。如果还有多解,y应该尽量小。

分析:

       本题详解见:刘汝佳训练指南P201

       建立一棵线段树,每个节点维护下面3种信息:

       max_sub:本节点维护的最大连续和的子区间[L,R]

       max_prefix:本节点的最大前缀和区间的右端坐标R

       max_suffix:本节点的最大后缀和区间的左端坐标L

来自:https://blog.csdn.net/u013480600/article/details/22225839

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define lson i*2,l,m
#define rson i*2+1,m+1,r
const int MAXN=500000+1000;
typedef long long LL;
typedef pair<int ,int> interval;
interval max_sub[MAXN*4];
int max_prefix[MAXN*4], max_suffix[MAXN*4];
LL prefix_sum[MAXN];
//max_sub:本节点维护的最大连续和的子区间[L,R]
//max_prefix:本节点的最大前缀和区间的右端坐标R
//max_suffix:本节点的最大后缀和区间的左端坐标L
LL get_sum(int L,int R)
{return prefix_sum[R]-prefix_sum[L-1];
}
LL get_sum(interval p)
{return get_sum(p.first, p.second);
}
interval better(interval a, interval b)
{if(get_sum(a) != get_sum(b)) return get_sum(a) > get_sum(b) ? a : b ;return a < b ? a : b;
}
void PushUp(int i,int l,int r)
{//计算最大和max_sub[i] = better(max_sub[i*2], max_sub[i*2+1]);max_sub[i] = better(max_sub[i], make_pair(max_suffix[i*2], max_prefix[i*2+1]));//计算前缀LL v1 = get_sum(l, max_prefix[i*2]);LL v2 = get_sum(l, max_prefix[i*2+1]);if(v1 == v2) max_prefix[i] = min(max_prefix[i*2], max_prefix[i*2+1]);else max_prefix[i] = v1 > v2 ? max_prefix[i*2] : max_prefix[i*2+1];//计算后缀v1 = get_sum(max_suffix[i*2], r);v2 = get_sum(max_suffix[i*2+1], r);if(v1 == v2) max_suffix[i] = min(max_suffix[i*2], max_suffix[i*2+1]);else max_suffix[i] = v1 > v2 ? max_suffix[i*2] : max_suffix[i*2+1];
}
void build(int i,int l,int r)
{if(l==r){max_sub[i]=make_pair(l, r);max_prefix[i]=max_suffix[i]=l;//printf("l=%d,r=%d,interval is [%d,%d]\n",l,r,max_sub[i].first,max_sub[i].second);return ;}int m=(l+r)/2;build(lson);build(rson);if(l==1&&r==2){int x=1;int y=1;}PushUp(i,l,r);
}
interval query_prefix(int ql, int qr, int i, int l, int r)//调用该函数的前提是:[ql,qr]包含了左端点l
{if(max_prefix[i] <= qr) return make_pair(l, max_prefix[i]);else{int m = (l+r)/2;if(qr <= m) return query_prefix(ql,qr,lson);interval a = query_prefix(ql,qr,rson);a.first = l;return better(a, make_pair(l, max_prefix[i*2]));}
}
interval query_suffix(int ql, int qr, int i, int l, int r)//调用该函数的前提是:[ql,qr]包含了右端点r
{if(max_suffix[i] >= ql) return make_pair(max_suffix[i], r);else{int m = (l+r)/2;if(m < ql) return query_suffix(ql,qr,rson);interval a = query_suffix(ql,qr,lson);a.second = r;return better(a, make_pair(max_suffix[i*2+1], r));}
}
interval query(int ql,int qr,int i,int l,int r)//返回[ql,qr]与[l,r]相交的最大连续和区间
{if(ql<=l && r<=qr) return max_sub[i];else{int m = (l+r)/2;if(qr<=m) return query(ql,qr,lson);if(ql>m) return query(ql,qr,rson);int L = query_suffix(ql,qr,lson).first;int R = query_prefix(ql,qr,rson).second;interval a = better(query(ql,qr,lson), query(ql,qr,rson));return better(make_pair(L, R), a);}
}
int main()
{int n,m;int kase=1;while(scanf("%d%d",&n,&m)==2&&n&&m){prefix_sum[0]=0;for(int i=1;i<=n;i++){int x;scanf("%d",&x);prefix_sum[i] = prefix_sum[i-1] + x;}build(1,1,n);printf("Case %d:\n",kase++);while(m--){int x,y;scanf("%d%d",&x,&y);interval a = query(x,y,1,1,n);printf("%d %d\n",a.first,a.second);}}return 0;
}


 

  相关解决方案