cogs755 山海經

775. 山海經

★★★   輸入文件:hill.in   輸出文件:hill.out   簡單對比
時間限制:1 s   內存限制:128 MB

【問題描述】

“南山之首日鵲山。其首日招搖之山,臨於西海之上,多桂,多金玉。有草焉,其狀如韭而青華,其名日祝餘,食之不飢……又東三百里,日堂庭之山,多棪木,多白猿,多水玉,多黃金。

又東三百八十里,日猨翼之山,其中多怪獸,水多怪魚,多白玉,多蝮蟲,多怪蛇,名怪木,不可以上。……”

《山海經》是以山爲綱,以海爲線記載古代的河流、植物、動物及礦產等情況,而且每一條記錄路線都不會有重複的山出現。某天,你的地理老師想重遊《山海經》中的路線,爲了簡化問題,老師已經把每座山用一個整數表示他對該山的喜惡程度,他想知道第a座山到第b座山的中間某段路(i,j)。能使他感到最滿意,即(i,j)這條路上所有山的喜惡度之和是(c,d)(a≤c≤d≤b)最大值。於是老師便向你請教,你能幫助他嗎?值得注意的是,在《山海經》中,第i座山只能到達第i+1座山。


【輸入】

輸入第1行是兩個數,n,m,2≤n≤100000,1≤m≤100000,n表示一共有n座山,m表示老師想查詢的數目。

第2行是n個整數,代表n座山的喜惡度,絕對值均小於10000。

以下m行每行有a,b兩個數,1≤a≤j≤b≤m,表示第a座山到第b座山。


【輸出】

一共有m行,每行有3個數i,j,s,表示從第i座山到第j座山總的喜惡度爲s。顯然,對於每個查詢,有a≤i≤j≤b,如果有多組解,則輸出i最小的,如果i也相等,則輸出j最小的解。


【輸入樣例】

5 3

5 -6 3 -1 4

1 3

1 5

5 5

【輸出樣例】

1 1 5

3 5 6

5 5 4


正解爲線段樹。題意大概爲求區間最長連續和。

首先,考慮結果的來源只有三個地方,區間前綴,區間後綴和區間的中間,所以要維護這三個變量,答案就是三者之一。
定義四個變量sum,lmax,rmax,ma,分別表示區間和,最大前綴和,最大後綴和,最大中間和。爲了維護詢問的左右邊界,定義lpos爲區間最大前綴和的右邊界,rpos爲區間最大後綴和的左邊界,ml,mr爲中間和的左右邊界。那麼很容易想到以下合併方法

(z爲當前節點,lch,rch分別爲左右子節點)

1. tr[z].lmax=max(tr[lch].lmax,tr[lch].sum+tr[rch].lmax);

2. tr[z].rmax=max(tr[rch].rmax,tr[rch].sum+tr[lch].rmax);

3. tr[z].ma=max(tr[lch].ma,tr[rch].ma,tr[lch].rmax+tr[rch].lmax);

在維護值時同時把下標維護(注意大小相同時按題目要求處理,因爲這WA了2次)

接下來是查詢,我們可以換一下思路,把以往線段樹查詢的點換爲一條線段,那麼這條線段就可以用上面的三種方法維護,最終結果就是你查詢得到的那條線段的lmax,rmax,ma的最大值。

#include<cstdio>
#define maxn 400005
using namespace std;
int n,m,inf=0xfffffff;
struct tree{int lc,rc,sum,lmax,rmax,ma,lpos,rpos,ml,mr;tree(){lmax=rmax=ma=-inf;sum=0;}}tr[maxn];
void pushup(int x)
{
	int lch=x<<1,rch=lch|1;
	tr[x].sum=tr[lch].sum+tr[rch].sum;
	if(tr[lch].lmax<tr[lch].sum+tr[rch].lmax) tr[x].lmax=tr[lch].sum+tr[rch].lmax,tr[x].lpos=tr[rch].lpos;
	else tr[x].lmax=tr[lch].lmax,tr[x].lpos=tr[lch].lpos;
	if(tr[rch].rmax<tr[rch].sum+tr[lch].rmax) tr[x].rmax=tr[rch].sum+tr[lch].rmax,tr[x].rpos=tr[lch].rpos;
	else tr[x].rmax=tr[rch].rmax,tr[x].rpos=tr[rch].rpos;
	if(tr[lch].ma<tr[rch].ma)
	{
		if(tr[rch].ma<=tr[lch].rmax+tr[rch].lmax) tr[x].ma=tr[lch].rmax+tr[rch].lmax,tr[x].ml=tr[lch].rpos,tr[x].mr=tr[rch].lpos;
		else tr[x].ma=tr[rch].ma,tr[x].ml=tr[rch].ml,tr[x].mr=tr[rch].mr;
	}
	else if(tr[lch].ma<tr[lch].rmax+tr[rch].lmax) tr[x].ma=tr[lch].rmax+tr[rch].lmax,tr[x].ml=tr[lch].rpos,tr[x].mr=tr[rch].lpos;
	else if(tr[lch].ma==tr[lch].rmax+tr[rch].lmax)
		 {	 tr[x].ma=tr[lch].ma;
			 if(tr[lch].rpos<tr[lch].ml) tr[x].ml=tr[lch].rpos,tr[x].mr=tr[rch].lpos;
			 else tr[x].ml=tr[lch].ml,tr[x].mr=tr[lch].mr;
		 }
	else tr[x].ma=tr[lch].ma,tr[x].ml=tr[lch].ml,tr[x].mr=tr[lch].mr;
}
void cmp(tree x,tree y,tree &z)
{
	z.lc=x.lc;z.rc=y.rc;
	z.sum=x.sum+y.sum;
	if(x.lmax<x.sum+y.lmax) z.lmax=x.sum+y.lmax,z.lpos=y.lpos;
	else z.lmax=x.lmax,z.lpos=x.lpos;
	if(y.rmax<y.sum+x.rmax) z.rmax=y.sum+x.rmax,z.rpos=x.rpos;
	else z.rmax=y.rmax,z.rpos=y.rpos;
	if(x.ma<y.ma)
	{
		if(y.ma<=x.rmax+y.lmax) z.ma=x.rmax+y.lmax,z.ml=x.rpos,z.mr=y.lpos;
		else z.ma=y.ma,z.ml=y.ml,z.mr=y.mr;
	}
	else if(x.ma<x.rmax+y.lmax) z.ma=x.rmax+y.lmax,z.ml=x.rpos,z.mr=y.lpos;
	else if(x.ma==x.rmax+y.lmax)
		 {	 z.ma=x.ma;
			 if(x.rpos<x.ml) z.ml=x.rpos,z.mr=y.lpos;
			 else z.ml=x.ml,z.mr=x.mr;
		 }
	else z.ma=x.ma,z.ml=x.ml,z.mr=x.mr;
}
void build(int x,int y,int z)
{
	tr[z].lc=x;tr[z].rc=y;
	if(x==y)
	{
		int tmp;scanf("%d",&tmp);
		tr[z].sum=tr[z].lmax=tr[z].rmax=tr[z].ma=tmp;
		tr[z].lpos=tr[z].rpos=tr[z].ml=tr[z].mr=x;
		return;
	}
	int mid=x+y>>1,lch=z<<1,rch=lch|1;
	build(x,mid,lch);build(mid+1,y,rch);
	pushup(z);
}
tree query(int x,int y,int z)
{
	if(tr[z].lc>=x&&tr[z].rc<=y)
		return tr[z];
	int mid=tr[z].lc+tr[z].rc>>1,lch=z<<1,rch=lch|1;tree t1,t2,t3;
	if(x<=mid) t1=query(x,y,lch);
	if(mid<y) t2=query(x,y,rch);
	t1.lc=x;t1.rc=mid;t2.lc=mid+1;t2.rc=y;
	cmp(t1,t2,t3);
	return t3;
}
void print(tree x)
{
	if(x.lmax>=x.rmax)
	{
		if(x.lmax>=x.ma) printf("%d %d %d\n",x.lc,x.lpos,x.lmax);
		else printf("%d %d %d\n",x.ml,x.mr,x.ma);
	}
	else if(x.rmax>x.ma) printf("%d %d %d\n",x.rpos,x.rc,x.rmax);
	else printf("%d %d %d\n",x.ml,x.mr,x.ma);
}
int main()
{
	freopen("hill.in","r",stdin);
	freopen("hill.out","w",stdout);
	scanf("%d%d",&n,&m);
	build(1,n,1);int x,y;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		tree tmp=query(x,y,1);
		print(tmp);
	}
	return 0;
} 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章