【LA3938】"Ray, Pass me the dishes!"

原题链接

Description

After doing Ray a great favor to collect sticks for Ray, Poor Neal becomes very hungry. In returnfor 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 (actually this line is very long……, the dishes are represented by 1, 2, 3……). "You make me work hard and don't pay me! You refuse to teach me Latin Dance! Now it is timefor you to serve me", Neal says to himself.
Every dish has its own value represented by an integer whose absolute value is less than 1,000,000,000.Before having dinner, Neal is wondering about the total value of the dishes he will eat. So he raises many questions about the values of dishes he would have.
For each question Neal asks, he will rst write down an interval [a,b] (inclusive) to represent all
the dishes a,a+1,……,b, where a and b are positive integers, and then asks Ray which sequence ofconsecutive dishes in the interval has the most total value.
Now Ray needs your help

Input

he input le contains multiple test cases. For each test case, there are two integers n,m in the rst line ((n,m < 500000)).
n is the number of dishes and m is the number of questions Neal asks.
Then n numbers come in the second line, which are the values of the dishes from left to right. Next m lines are the questions and each line contains two numbers a,b as described above. Proceed to the end of the input .

Output

For each test case, output mlines. Each line contains two numbers, indicating the beginning position and end position of the sequence. If there are multiple solutions, output the one with the smallest beginning position. If there are still multiple solutions then, just output the one with the smallest end position. Please output the result as in the Sample Output

Sample Input

3 1
1 2 3
1 1

Sample Output

1 1

Solution

显然,这是一个裸的区间内最大子段和问题,但是需要注意的是至少需要取一个数,并且多解输出区间尽可能靠左的。
首先讲一下解决最大子段和问题的思路:
维护三种信息:最大左子段和(意思是包含区间左端点的子段和)(记为lx),最大右子段和(记为rx),以及区间最大字段和(记为mx),然后线段树维护上述三种信息即可。
对于区间([l,r]) 我们可以按照如下方式维护信息:

$lx_{[l,r]}=max(lx_{[l,mid]},lx_{[mid+1,r]}+sum_{[l,mid]}) $

rx同理不多赘述
$mx_{[l,r]}=max(mx_{[l,mid]},mx_{[mid+1,r]},rx_{[l,mid]}+lx_{[mid+1,r]}) $

可以zkw线段树书写,时间效率(O(m log_{2} n))

Code

#include <stdio.h>
#define MN 500005
#define M (1<<18)
#define R register
#define ll long long
inline int read(){
	R int x; R char c; R bool f;
	for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
	for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
	return f?-x:x;
}
ll pre[MN],n,q,m;
struct node{
	int l,r;
	node(int l=0,int r=0):l(l),r(r){};
};
inline ll sum(int l,int r){return pre[r]-pre[l-1];}
inline ll sum(node &p){return sum(p.l,p.r);}
inline bool operator >(node a,node b){return sum(a)>sum(b)||(sum(a)==sum(b)&&(a.l<b.l||(a.l==b.l&&a.r<b.r)));}
inline node max(node a,node b){return a>b?a:b;}
struct data{node l,r,m;bool p;data(node l,node r,node m):l(l),r(r),m(m){p=1;} data(){p=1;}};
inline data operator +(data a,data b){
	if (!a.p) return b; if (!b.p) return a;
	R data c;c.l=max(a.l,node(a.l.l,b.l.r));
	c.r=max(b.r,node(a.r.l,b.r.r));
	c.m=max(max(a.m,b.m),node(a.r.l,b.l.r));return c;
}
data T[M<<1];
inline data query(int l,int r){
	R data lans,rans;lans.p=0,rans.p=0;
	for (l+=m-1,r+=m+1; l^r^1; l>>=1,r>>=1){
		if (~l&1) lans=lans+T[l^1];
		if ( r&1) rans=T[r^1]+rans;
	}return lans+rans;
}
inline void work(){
	for (m=1; m<n+2; m<<=1);pre[0]=0;
	for (R int i=1; i<=n; ++i) pre[i]=pre[i-1]+read(),T[m+i]=data(node(i,i),node(i,i),node(i,i));
	for (R int i=n+m+1; i<=(m-1<<1); ++i) T[i].p=0;T[m].p=0;
	for (R int i=m-1; i; --i) T[i]=T[i<<1]+T[i<<1|1];
	for (R int i=1; i<=q; ++i){
		R int l=read(),r=read();
		R data ans=query(l,r);if (!ans.m.r) ans.m.r=ans.m.l;
		printf("%d %d
",ans.m.l,ans.m.r);
	}
}
int main(){for (R int cnt=1; ~scanf("%d%d",&n,&q); ++cnt) printf("Case %d:
",cnt),work();}
原文地址:https://www.cnblogs.com/Melacau/p/LA3938.html