B-Find the minimum value of the hillside line segment tree maintenance interval + discretization

Link: https://ac.nowcoder.com/acm/contest/13504/B
Source : Niuke.com . Niu
brother sat in front of the computer for a long time. He wanted to stand up and look at the small hill outside the window, so he came up with this Question:
Given an array a of size n, the sequence number starts from 1,
calculate:
max{ R-L | 1 <= L <= R <= n, a[L] == a[R], for all i (L <= i <= R), satisfy a[i] >= a[L] }.
That is to find two coordinates, the values ​​of these two coordinates are equal, and the value between them is greater than or equal to these two The value on the coordinates.
What is the maximum subtraction of these two coordinates.

示例1
输入

复制
5
1 2 3 2 1
输出

复制
4

Idea: Linear traversal, use line segment tree to maintain the minimum interval

AC code:

#include<iostream>
#include<vector>
#include<map>
using namespace std;
const int maxn=1e6+10;
int arr[maxn];
int Min[maxn<<2];
map<int,int>fi; // 数字最小下标
vector<int>vec[maxn];
int read() {
    
    
    int x = 0, w = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
    
      // ch 不是数字时
        if (ch == '-') w = -1;        // 判断是否为负
        ch = getchar();               // 继续读入
    }
    while (ch >= '0' && ch <= '9') {
    
      // ch 是数字时
        x = x * 10 + (ch - '0');  // 将新读入的数字’加’在 x 的后面
        // x 是 int 类型,char 类型的 ch 和 ’0’ 会被自动转为其对应的
        // ASCII 码,相当于将 ch 转化为对应数字
        // 此处也可以使用 (x<<3)+(x<<1) 的写法来代替 x*10
        ch = getchar();  // 继续读入
    }
    return x * w;  // 数字 * 正负号 = 实际数值
}

int min(int x,int y)
{
    
    
    return (x<y)?x:y;
}
void PushUp(int rt)
{
    
    
    Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
}
void build(int l, int r, int rt)
{
    
    
    if( l == r ){
    
    
        Min[rt]=arr[l];
        return ;
    }
    int mid =( l + r ) >> 1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    PushUp(rt);
}
int query(int i, int j, int l , int r, int rt)
{
    
    
    if(i<=l && j>=r)
        return Min[rt];
    int mid=(l + r) >> 1;
    int ans=0x3f3f3f3f;
    if(i <= mid)
        ans = min(ans,query(i ,j ,l ,mid ,rt<<1));
    if(j > mid)
        ans = min(ans,query(i ,j ,mid+1 ,r,rt<<1|1));
    return ans;
}


int main()
{
    
    
    int n;
//    cin>>n;
    n=read();
    for(int i=1;i<=n;i++){
    
    
//        cin>>arr[i];
        arr[i]=read();
        if(fi[arr[i]]==0){
    
    
            fi[arr[i]]=i;
        }
        else{
    
    
            vec[fi[arr[i]]].push_back(i); // fi[arr[i]]是将输入数字离散化 因为输入数字范围是1e9 ,使用数字首次出现下标来进行离散化
        }
    }
    int ans=0;
    build(1,n,1);//线段树区间最小值
    map<int,int>::iterator iter;
    for(iter=fi.begin();iter!=fi.end();iter++){
    
    
        int num = (*iter).first;
//        cout<<"num="<<num<<endl;
        int l_pos = fi[num],sz=vec[fi[num]].size();
        for (int i=0;i<sz;i++){
    
    
            int r_pos = vec[fi[num]][i];
//            cout<<"r_pos="<<r_pos<<"    l_pos="<<l_pos<<endl;
            if(query(l_pos,r_pos,1,n,1)>=num){
    
    //区间最小值>=num
                //更新答案
                ans=max(ans,r_pos-l_pos); //坐标相减
            }
            else{
    
    //说明[l,r]区间有小于num的数,则应该修改左端点l为当然r 这样遍历是线性的
                l_pos = r_pos;
            }
        }
    }
    cout<<ans<<endl;

}


Guess you like

Origin blog.csdn.net/weixin_56336619/article/details/115268405