【POJ-2452】Sticks Problem【二分右端点+线段树】

题意:

      给定一个数组序列,找到一段区间 [ i , j ],使得区间a[i] < a[k] < a[j],( k 是 [ i , j ] 中任意一个数),此处注意 a[i] 是区间唯一最小值,a[j] 是区间唯一最大值。

      求 j-i 最大值。(n <= 50000)

思路:

      确定左端点,然后找到一个最长区间,使得该区间的最小值为左端点这个值,然后再求出这个区间的最大值,更新答案即可。

      所以现在的问题就变成了如何求出最长区间,使得区间最小值为左端点这个值。

      最简单的思路就是枚举了,但是时间复杂度上肯定不可行,因此可以考虑进行二分查询,二分右端点,判断这个区间的最小值是否为左端点,即可求出最长的可行区间。

      因为不涉及修改,所以如果用 st 表的话,时间复杂度为O(nlogn),如果用线段树的话,时间复杂度为O(n(logn^2)),可能会过不去,需要在二分的时候进行一些优化操作。

总结:

      这是一个基础的 线段树+二分 问题,一直T了好久,还是需要加强码力才行。

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
const int N = 50000+1000;
const int inf = 0x3fffffff;

int n,a[N],lar[N];
struct Tree{
	int l,r;
	int minn,maxn;
	int pos;
}t[4*N];

inline int gi()
{
  int date = 0,m = 1; char ch = 0;
  while(ch!='-'&&(ch<'0'||ch>'9'))ch = getchar();
  if(ch=='-'){m = -1; ch = getchar();}
  while(ch>='0' && ch<='9')
    {
      date = date*10+ch-'0';
      ch = getchar();
    }return date*m;
}

void build(int p,int l,int r)
{
	t[p].l = l, t[p].r = r;
	if(l == r){
		t[p].maxn = t[p].minn = a[l];
		t[p].pos = l;
		return;
	}
	int mid = (l+r)>>1;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	
	if(t[p*2].maxn > t[p*2+1].maxn) 
		t[p].maxn = t[p*2].maxn, t[p].pos = t[p*2].pos;
	else 
		t[p].maxn = t[p*2+1].maxn, t[p].pos = t[p*2+1].pos; 
	t[p].minn = min(t[p*2].minn,t[p*2+1].minn);
}

int ask_min(int p,int l,int r)
{
	if(l <= t[p].l && r >= t[p].r) return t[p].minn;
	int mid = (t[p].l+t[p].r)>>1;
	int val = inf;
	if(l <= mid) val = min(val,ask_min(p*2,l,r));
	if(r > mid) val = min(val,ask_min(p*2+1,l,r));
	return val;
}

pair<int,int> ask_max(int p,int l,int r)
{
	if(l <= t[p].l && r >= t[p].r) return make_pair(t[p].maxn,t[p].pos);
	int mid = (t[p].l+t[p].r)>>1;
	pair<int,int> tmp(-1,0),tp1;
	if(l <= mid){
		tp1 = ask_max(p*2,l,r);
		if(tmp < tp1) tmp = tp1;
		else if(tmp == tp1) tmp.second = min(tmp.second,tp1.second);	
	} 
	if(r > mid){
		tp1 = ask_max(p*2+1,l,r);
		if(tmp < tp1) tmp = tp1;
		else if(tmp == tp1) tmp.second = min(tmp.second,tp1.second);	
	} 
	return tmp;		
}

int main()
{
//	while(~scanf("%d",&n))
	while(scanf("%d", &n) != EOF)
	{
		rep(i,1,n) a[i] = gi();
		int ans = -1;
		build(1,1,n);
		rep(i,1,n){
			int l = i+1,r = n,cr = -1;
			while(l <= r){
				int mid = (l+r)>>1;
				if((mid-i) <= ans){
					l = mid+1;
					continue;
				}
				int tmp = ask_min(1,i,mid);
			//	printf("i:%d,mid:%d,tmp:%d\n",i,mid,tmp);
				if(tmp < a[i]) r = mid-1;
				else cr = mid, l = mid+1;
			}
		//	printf("cr:%d\n",cr);
			if(cr != -1 && (cr-i) > ans){
				pair<int,int> tmp = ask_max(1,i,cr);
				if(tmp.first > a[i])
					ans = max(ans,tmp.second-i);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/83002562