Balanced Lineup

For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.

Input

Line 1: Two space-separated integers, N and Q
Lines 2.. N+1: Line i+1 contains a single integer that is the height of cow i 
Lines N+2.. NQ+1: Two integers A and B (1 ≤ A ≤ B ≤ N), representing the range of cows from A to B inclusive.

Output

Lines 1.. Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.

Sample Input

6 3
1
7
3
4
2
5
1 5
4 6
2 2

Sample Output

6
3
0

C++版本一

#include 
#include 
#include 
#include 
#include 
using namespace std;
int t,n,q;
long tree1[50010<<2];
long tree2[50010<<2];
long a[50010];
void PushUp(int rt){
    tree1[rt] =max(tree1[rt*2] , tree1[rt*2+1]) ; ///区间和的更新操作
    tree2[rt] =min(tree2[rt*2] , tree2[rt*2+1]) ;
}

void Build(int l,int r,int rt){
    // l,r 代表的是这个区间内的左端点 和 右端点, rt代表的是 [l,r] 这个区间内的值是存在哪一个位置的。
    if(l==r){
        //scanf("%d",&tree[rt]);
         tree1[rt] = a[l];
         tree2[rt] = a[l];
        return;
    }
    int m=(l+r)/2;// 对于区间区分,我们一般将m点划入左半边区间
    Build(l,m,rt*2);
    Build(m+1,r,rt*2+1);
    PushUp(rt); // PushUp 函数是通过2个子节点来更新现在这个节点的状态, 对于不同的要求需要不同的写法。

}
long MAXQuery(int l,int r,int rt,int L,int R){// [L,R]为查询区间
    if(L <= l && r <= R){
        return tree1[rt];// 如果成立则满足查询区间覆盖了当前区间, 直接返回当前区间的值
    }
    int m=(l+r)/2;
    long res=0;
    if(L<=m)    res=max(res,MAXQuery(l,m,rt*2,L,R));//左边有一部分需要查询的区域。
    if(m

C++版本二

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
using namespace std;
 
const int MAX = 5e4+10;
const double eps = 1e-8;
const double PI = acos(-1.0);
struct node
{
    int minn, maxx;
}lxt[MAX*6];
int a[MAX];
int n, q, r, l;
void build(int l, int r, int pos)
{
    if(l==r)
    {
        scanf("%d", &lxt[pos].minn);
        lxt[pos].maxx = lxt[pos].minn;
    }
    else
    {
        build(l, (l+r)/2, pos*2);
        build((l+r)/2+1, r, pos*2+1);
        lxt[pos].maxx = max(lxt[pos*2+1].maxx, lxt[pos*2].maxx);
        lxt[pos].minn = min(lxt[pos*2+1].minn, lxt[pos*2].minn);
    }
    //printf("%d %d %d %d \n", l, r, lxt[pos].maxx, lxt[pos].minn);
}
int check1(int l, int r, int ll, int rr, int pos)
{
    if(ll==l&&rr==r)return lxt[pos].maxx;
    else
    {
        int mid = (ll+rr)/2;
        if(r<=rr&&l>mid)return check1(l,r,mid+1, rr, pos*2+1);
        else if(r<=mid&&l>=ll)return check1(l,r,ll,mid,pos*2);
        else
        {
            return max(check1(l, mid, ll, mid, pos*2),check1(mid+1, r, mid+1, rr, pos*2+1));
        }
    }
}
int check2(int l, int r, int ll, int rr, int pos)
{
    if(ll==l&&rr==r)return lxt[pos].minn;
    else
    {
        int mid = (ll+rr)/2;
        if(r<=rr&&l>mid)return check2(l,r,mid+1, rr, pos*2+1);
        else if(r<=mid&&l>=ll)return check2(l,r,ll,mid,pos*2);
        else
        {
            return min(check2(l, mid, ll, mid, pos*2),check2(mid+1, r, mid+1, rr, pos*2+1));
        }
    }
}
int main()
{
    while(~scanf("%d%d", &n, &q))
    {
        build(1, n, 1);
        //for(int i =1; i<=50; ++i)
        //printf("%d %d\n", lxt[i].maxx, lxt[i].minn);
        while(q--)
        {
            scanf("%d%d", &l, &r);
            if(l>r)swap(l,r);
            printf("%d\n", check1(l,r,1,n,1)-check2(l,r,1,n,1));
        }
    }
    return 0;
}

C++版本三

题目大意:

一个农夫有N头牛,每头牛的高度不同,我们需要找出最高的牛和最低的牛的高度差。

解题思路:

我是用RMQ写的。

N为50000,Q为200000,如果我们暴力的话,需要50000*200000=10000000000,需要25s左右.所以我们需要高效的算法,而RMQ正好解决的就是区间最值问题,复杂度为nlogn,这样就可以了。

另外还可以用线段树,因为线段树的别名就是区间树。segment tree
 

#include
#include
#include
#include
#include
#include
using namespace std;
 
const int N = 50005;
int FMAX[N][20], FMIN[N][20];
 
void RMQ(int n)
{
	for(int j = 1; j != 20; ++j)
	{
		for(int i = 1; i <= n; ++i)
		{
			if(i + (1 << j) - 1 <= n)
			{
				FMAX[i][j] = max(FMAX[i][j - 1], FMAX[i + (1 << (j - 1))][j - 1]);
				FMIN[i][j] = min(FMIN[i][j - 1], FMIN[i + (1 << (j - 1))][j - 1]);
			}
		}
	}
}
 
int main()
{
	int num, query;
	int a, b;
	while(scanf("%d %d", &num, &query) != EOF)
	{
		for(int i = 1; i <= num; ++i)
		{
			scanf("%d", &FMAX[i][0]);
			FMIN[i][0] = FMAX[i][0];
		}
		RMQ(num);
		while(query--)
		{
			scanf("%d%d", &a, &b);
			int k = (int)(log(b - a + 1.0) / log(2.0));
			int maxsum = max(FMAX[a][k], FMAX[b - (1 << k) + 1][k]);
			int minsum = min(FMIN[a][k], FMIN[b - (1 << k) + 1][k]);
			printf("%d\n", maxsum - minsum);
		}
	}
	return 0;
}

C++版本四

这道题目的确出的很好

首先是题意的转换,怎么去寻找最大的距离

那么我们看例子


7 3
7
6
7
2
1
4
2
转化为2进制

111

110

111

010

001

100

010

逐个累加

111

221

332

342

343

443

453

分别减去最右边的数

000

110《----

110

120

010
110《----

120

就可以发现是2和6是最远的相同数字,那么只用6-2=4即可算出答案

 

那到底为什么这么做就对了呢?

为什么两个数一样就得到了正确解了呢。

可以这么理解,当两个数相同时,说明在这两个数之间出现的数在每个特征上出现的数目相同,否则是不会两个数相同的。因为只有最右边的那个数增加了和左边所有的数增加的数字相同,他们才会减去最右边的数,出现相同

 

接着可以用HASH,也可以用MAP,我觉得不需要用MULTIMAP,因为只需要记录每个数字形式出现的最早时期即可。

注意给HASH函数加上0000000000这种情况
 

#include
#include
const int N=100100;
const int prime=100003;
int sum[N][32],c[N][32];
int hash[N];
int hashcode(int* v,int k)
{
    int p;
    for(int i=1;i<=k;i++)  p=((p<<2)+(v[i]>>4))^(v[i]<<10);
    p=p%prime;
    if(p<0)  p=p+prime;
    return p;
}
int main()
{
    //freopen("lineup.10.in","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,k;
    int ans=0;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        memset(sum,0,sizeof(sum));
        memset(hash,-1,sizeof(hash));
        memset(c,0,sizeof(c));
        hash[hashcode(c[0],k)]=0;
        ans=0;
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            for(int j=1;j<=k;j++)
            {
                sum[i][j]=sum[i-1][j]+x%2;
                c[i][j]=sum[i][j]-sum[i][1];
                x=x>>1;
            }
           int p=hashcode(c[i],k);
           while(hash[p]!=-1)
            {
                int j;
                for(j=1;j<=k;j++)
                    if(c[i][j]!=c[hash[p]][j])  break;
                if(j==k+1)
                {
                    if(i-hash[p]>ans)  ans=i-hash[p];
                    break;
                }
                p++;
            }
            if(hash[p]==-1)  hash[p]=i;
        }
        printf("%d/n",ans);
    }
    return 0;
}

C++版本五

题解:ST表

https://blog.csdn.net/weixin_43272781/article/details/88386252

/*
*@Author:   STZG
*@Language: C++
*/
//#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#define DEBUG
#define RI register int
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,q;
int ans,cnt,flag,temp;
ll maxl[N][21],minl[N][21];
void RMQ_ST(){
    for(int i=0;i<20;i++){
        for(int j=1;j+(1<

 

你可能感兴趣的:(#,C++,C,线段树,RMQ,ST表)