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]}を満たします。
つまり、2つの座標を見つけ、これら2つの座標の値は等しく、値はそれらの間は、これら2つ以上です。座標の値。
これら2つの座標の最大減算はいくつですか。

示例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