リンク: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;
}