B- 산비탈 선분 트리 유지 보수 간격 + 이산화의 최소값 찾기

링크 : https://ac.nowcoder.com/acm/contest/13504/B
출처 : Niuke.com , Niu
형제는 오랫동안 컴퓨터 앞에 앉아 일어 서서 바깥 쪽의 작은 언덕을보고 싶었습니다. 그래서 그는 다음과 같은 질문을했습니다.
크기가 n 인 배열 a가 주어지면 시퀀스 번호는 1부터 시작
하여 다음을 계산합니다.
max {RL | 1 <= L <= R <= n, a [L] == a [ R], 모든 i (L <= i <= R)에 대해 a [i]> = a [L]}을 충족합니다.
즉, 두 좌표를 찾으려면이 두 좌표의 값이 같고 값이 그들 사이는이 두 좌표보다 크거나 같음이 두 좌표
의 최대 뺄셈은 얼마입니까?

示例1
输入

复制
5
1 2 3 2 1
输出

复制
4

아이디어 : 선형 순회, 선분 트리를 사용하여 최소 간격 유지

AC 코드 :

#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;

}


추천

출처blog.csdn.net/weixin_56336619/article/details/115268405