hdu5289 Assignment (区间查询最大值最小值,st算法...)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5289

题意:给定长度为n的序列a和一个整数K,找出最大值和最小值的差值小于K的区间。输出满足条件的区间的个数。

分析:枚举a[i],以a[i]为起点,然后二分找终点(大区间满足条件的话小区间肯定也满足),依据起点和终点的位置能够算出以a[i]为起点可满足条件的区间的个数。怎么推断区间是否满足条件?能够用st算法用O(N*logN)方法进行预处理,然后O(1)查询区间最大值可最小值。先前用线段树查询超时了。。

后来还看到别人用树状数组+二分也过了。

还有的用队列写,或者直接线段树不二分。。。。

代码:

#include <iostream>
#include <cstdio>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 2e5;
int _max,_min,n,K;

int MAX[100006][20],MIN[100006][20],a[100006];
void Init()
{
	int i,j;
	for(i=0;i<n;i++)
		MAX[i][0]=MIN[i][0]=a[i];
	for(j=1;(1<<j)<=n;j++)
	{
		for(i=0;i+(1<<j)-1<n;i++)
		{
			MAX[i][j]=MAX[i][j-1]>MAX[i+(1<<(j-1))][j-1]?MAX[i][j-1]:MAX[i+(1<<(j-1))][j-1];
			MIN[i][j]=MIN[i][j-1]<MIN[i+(1<<(j-1))][j-1]?

MIN[i][j-1]:MIN[i+(1<<(j-1))][j-1];
		}
	}
}
bool ok(int L,int R)
{
	int k=0;
	while((1<<(k+1))<=(R-L+1))
		k++;
	_min=MIN[L][k]<MIN[R-(1<<k)+1][k]?MIN[L][k]:MIN[R-(1<<k)+1][k];
	_max=MAX[L][k]>MAX[R-(1<<k)+1][k]?MAX[L][k]:MAX[R-(1<<k)+1][k];
	return _max-_min<K;
}
int Find(int s)
{
	int down=s+1,up=n-1,mid,ret=s;
	while(down<=up)
	{
		mid=(down+up)>>1;
		if(!ok(s,mid))
			up=mid-1;
		else
		{
			down=mid+1;
			if(ret<mid)
				ret=mid;
		}
	}
	return ret;
}
int main()
{
	int ncase,i,j;
	long long ans;
	scanf("%d",&ncase);
	while(ncase--)
	{
		scanf("%d%d",&n,&K);
		for(i=0;i<n;i++)
			scanf("%d",&a[i]);
		Init();
		ans=n;
		for(i=0;i<n;i++)
			ans+=Find(i)-i;
		printf("%I64d\n",ans);
	}
	return 0;
}
时间: 2024-10-11 12:58:49

hdu5289 Assignment (区间查询最大值最小值,st算法...)的相关文章

poj--3264Balanced Lineup+ST算法求区间最大最小值

题目链接:点击进入 其实这种动态查询区间最大最小值的题目,解法是有很多的,像是线段树和树状数组都是可以做的.ST算法效率和上面两种是一样的,但是编码更为简单. ST算法是一种利用了递推思想进行计算的算法,令dp(i,j)表示从i开始长度为2^j的一段元素中的最小值,则dp(i,j)=min(dp(i,j-1),dp(i+2^(j-1),j-1)).这是求区间最小值的递归关系,其实求区间最大值也是一样的. 代码如下: #include<iostream> #include<cstring&

hdu 5289 Assignment 【ST算法】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289 题意:求满足最大值减最小值小于k的区间的数目. 枚举左端点,二分右端点,用st算法求区间最值 代码: #include <stdio.h> #include <ctime> #include <math.h> #include <limits.h> #include <complex> #include <string> #incl

学习笔记 ST算法

[引子]RMQ (Range Minimum/Maximum Query)问题: 对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题. {方法} 1.朴素(即搜索),O(n)-O(qn) online. 2.线段树,O(n)-O(qlogn) online. 3.ST(实质是动态规划),O(nlogn)-O(q) online. ST算法(Sparse Table),以求最大值为例,设d[i,

【RMQ】【ST算法】【模板】士兵杀敌(三)

描述 南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进行比较,计算出两个人的杀敌数差值,用这种方法一方面能鼓舞杀敌数高的人,另一方面也算是批评杀敌数低的人,起到了很好的效果. 所以,南将军经常问军师小工第i号士兵到第j号士兵中,杀敌数最高的人与杀敌数最低的人之间军功差值是多少. 现在,请你写一个程序,帮小工回答南将军每次的询问吧. 注意,南将军可能询问很多次. 输入 只有一组测试数据 第一行是两个整数N,Q,其中N表示士兵的总数.Q表示南将军

解题报告 之 HDU5289 Assignment

解题报告 之 HDU5289 Assignment Description Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this company, and every staff has a ability. Now, Tom is going to assign a special task to some staffs who were in the s

【动态规划dp】RMQ问题(st算法)

[RMQ] Range Minimum/Maximum Query  范围最值问题 [ST算法] 解决RMQ问题的有效算法 预处理   经过预处理构造出d,预处理时间复杂度 O(nlogn) 运用动态规划的思想   d(i, j) 表示 范围 i ~ i + 2j-1 的最小值则有状态转移方程 d(i, j) = min {      d(i, j-1)       ,    d(i + 2j-1 , j-1)     } 设原数据存储在数组a[]  , 则初始状态 d( i ,  0 ) =

POJ2019:二维ST算法解决静态方阵最值问题

我们其实是很有必要把ST算法拓展到二维的,因为二维的RMQ问题还是不少的 int N,B,K; int mm[505]; int val[maxn][maxn]; int dpmin[maxn][maxn][8][8]; int dpmax[maxn][maxn][8][8]; 这里的N是方阵的长宽,此处是正方形题目,然后mm是预处理出来的,方便计算指数 dpmin和dpmax就是预处理数组了 然后看一下开局预处理: void initRMQ(int n,int m) { for(int i=1

Tunnel Warfare (区间合并&amp;最大值最小值巧妙方法)

Tunnel Warfare http://acm.hdu.edu.cn/showproblem.php?pid=1540 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 13440    Accepted Submission(s): 5333 Problem Description During the War of Resistan

RMQ问题 ST算法

RMQ是询问某个区间的最大值或最小值的问题,主要求解方法之一ST算法: ST算法其实是倍增思想的产物,等下看代码实现就很明显了 ST算法通常用在要多次询问一些区间的最值的问题中,相比于线段树,它的程序实现更简单,运行速度更快; ST算法没有修改操作(或者说不擅长动态修改) ST算法流程: 预处理:ST算法的原理实际上是动态规划,我们用a数组表示一组数,设\(f[i,j]\)表示从\(a[i]\)到\(a[i+2^j-1]\)这个范围内的最大值,从中间平均分成两部分,即把\(f[i,j]\)分为\