码迷,mamicode.com
首页 > 其他好文 > 详细

[CodeVS]3304

时间:2015-05-02 19:31:57      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:st表   倍增算法   线段树   codevs   

【分析】

倍增算法 or 线段树。

笔者使用倍增算法。

扩充倍增算法,记录pre[K][N],mn[K][N],mx[K][N],l_r[K][N],r_l[K][N],分别保存对应节点,最小值,最大值,从左到右的答案,从右到左的答案。

首先奠定基础,pre[0][i]=max(i+1,n),mn[0][i]=min(value[i],value[pre[0][i]]),mx同理,l_r[0][i]=max(0,value[pre[0][i]]-value[i]),r_l同理。

然后转移,pre[i][j]=pre[i-1][pre[i-1][j]],mx[i][j]=max(mx[i-1][j],mx[i-1][pre[i-1][j]]),l_r[i][j]=max(l_r[i-1][j],l_r[i-1][pre[i-1][j]],mx[i-1][pre[i-1][j]]-mn[i-1][j]),r_l同理。

倍增预处理完成,接着查询。

分类讨论,若l<=r则从左往右跳,取当前区间值l_r和区间相差值的最大值,r<=l同理


【代码】

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;

const int N=200001;
const int K=20;
const int M=300000000;

int n,m,value[N];	//Basic
int pre[K][N],mx[K][N],mn[K][N],l_r[K][N],r_l[K][N],unit;	//Double

inline int min(int i,int j)
{
	return i<j?i:j;
}

inline int max(int i,int j)
{
	return i>j?i:j;
}

void init(void)
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&value[i]);
	
	for (int i=1;i<n;i++) pre[0][i]=i+1;
	pre[0][n]=n;
	for (int i=1;i<=n;i++)
	{
		mx[0][i]=max(value[i],value[pre[0][i]]);
		mn[0][i]=min(value[i],value[pre[0][i]]);
		l_r[0][i]=value[pre[0][i]]-value[i];
		r_l[0][i]=value[i]-value[pre[0][i]];
	}
	
	unit=log(n)/log(2);
	for (int i=1;i<=unit;i++)
		for (int j=1;j<=n;j++)
		{
			pre[i][j]=pre[i-1][pre[i-1][j]];
			mx[i][j]=max(mx[i-1][j],mx[i-1][pre[i-1][j]]);
			mn[i][j]=min(mn[i-1][j],mn[i-1][pre[i-1][j]]);
			l_r[i][j]=max(l_r[i-1][j],l_r[i-1][pre[i-1][j]]);
			l_r[i][j]=max(l_r[i][j],mx[i-1][pre[i-1][j]]-mn[i-1][j]);
			r_l[i][j]=max(r_l[i-1][j],r_l[i-1][pre[i-1][j]]);
			r_l[i][j]=max(r_l[i][j],mx[i-1][j]-mn[i-1][pre[i-1][j]]);
		}
}

inline int query(int l,int r)
{
	int res=0;
	if (l<=r)
	{
		int lrgo=M;
		for (int i=unit;i+1;i--)
			if (pre[i][l]<=r)
			{
				res=max(res,l_r[i][l]);
				res=max(res,mx[i][l]-lrgo);
				lrgo=min(lrgo,mn[i][l]);
				if ((l=pre[i][l])==r) break;
			}
	}
	else
	{
		int rlgo=0;
		l^=r^=l^=r;
		for (int i=unit;i+1;i--)
			if (pre[i][l]<=r)
			{
				res=max(res,r_l[i][l]);
				res=max(res,rlgo-mn[i][l]);
				rlgo=max(rlgo,mx[i][l]);
				if ((l=pre[i][l])==r) break;
			}
	}
	return res;
}

void work(void)
{
	int x,y;
	scanf("%d",&m);
	for (;m--;)
	{
		scanf("%d%d",&x,&y);
		printf("%d\n",query(x,y));
	}
}

int main(void)
{	
	init();
	work();
	
	return 0;
}


[CodeVS]3304

标签:st表   倍增算法   线段树   codevs   

原文地址:http://blog.csdn.net/u013598409/article/details/45441049

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!