2018HDU多校赛 HDU 6406 ( Taotao Picks Apples ) ST表+单调队列

题意见参考博客
题意相当于问你改变一个位置之后。
从左往右扫描最大值。这个最大值会改变多少次。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+7;
int a[N];
int n,m;
int Max(int i,int j)
{
    if(a[i]>=a[j])return i;//这里需要大于等于,也就是要去找小于q的数的最左边的那个
    //因为step数组的属性,只有最左边的那个数才存了东西,具体可以看如下数据进行验证
    else return j;
}
/*
1
6 1
2 2 2 3 3 3
3 4
*/
int  rmq[N][25];
int  mm[N];//最大的小于等于i的2^mm[i],即Log(2,i)
void initRMQ(int n)
{
   // mm[0] = -1;
    //rmq[0][0] = 0;
    for(int  i=0; i<=n; i++)
    {
       // mm[i] = ((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
        //预处理计算log(2,i)
        rmq[i][0] = i;
    }
    for(int  j=1; j<=17; j++)
        for(int i=1; i+(1<<j)-1<=n; i++)
            rmq[i][j] =Max(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]);
}
/*
        求解从x-y区间a数组最大值
*/
int RMQ(int  x,int  y)
{
    if(x>y)return 0;
    int  k = log2(y-x+1);
    return Max(rmq[x][k],rmq[y+1-(1<<k)][k]);
}
int get_higher(int pos,int x)
{
    int l = pos,r = n,tmp = -1;
    while(l<=r)
    {
        int m = (l+r)>>1;
        if(a[RMQ(pos,m)]>x)
        {
            tmp = m;
            r =m-1;
        }
        else
        {
            l = m+1;
        }
    }
    return tmp;
}
void debug(int  a[],int n)
{
    cout<<"数组a为"<<endl;
   int top = 1;
   for(int i=0;i<=n;i++)
   {
       if(top)top =0;
       else printf(" ");
       printf("%d",a[i]);
   }
   printf("\n");
}
int _size[N];
int ddz[N];
int pre[N];
//注意这里讲的上升序列是指题目中讲的从左到右
//遇到一个比当前值大的就进行更新。
//step数组含义 是从1开始,到
//当前数为止上升序列的长度,注意
//如果step数组不为0,那么a[i]一定是确定好的上升序列中的一个
//例如 1 2 3 4 4即使是相等,a[5]也是0;
//_size数组含义是单调栈的大小,代表从当前标号到最后上升序列的长度
//dl数组含义 是单调栈内元素的位置标号
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
       //memset(_size,0,sizeof (_size));
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        initRMQ(n);
        pre[1]  = 1;
        int cur = 1;
        for(int i=2; i<=n; i++)
        {
           // pre[i]  =0;
            if(a[cur]<a[i])
            {
                pre[i] = pre[cur]+1;
                cur = i;
            }
        }
        //倒着跑单调栈,用size数组记录大小
        int Front=0,Back  =1;
        for(int i=n; i>=1; i--)
        {
            while(Back<=Front&&a[i]>=a[ddz[Front]])Front--;
            ddz[++Front] = i;
            _size[i] = Front-Back+1;
        }
       debug(pre,n);
       debug(_size,n);
       debug(ddz,n);
        for(int j=1; j<=m; j++)
        {
            int ans= 0;
            int p,q;
            scanf("%d%d",&p,&q);
            int idx = RMQ(1,p-1);
           //cout<<idx<<endl;
           int key = q;
            if(a[idx]>=q)
            {
                key = a[idx];
                ans= -1;
            }
            int idx2 = get_higher(p+1,key);
            //cout<<idx2<<endl;
            if(idx2==-1)
            {
                ans+=pre[idx]+1;
                printf("%d\n",ans);
            }
            else
            {
                ans+=pre[idx]+1+_size[idx2];
                printf("%d\n",ans);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/axuhongbo/article/details/81774160
今日推荐