B-找山坡 2021年广东工业大学第十五届文远知行杯程序设计竞赛(同步赛)
母牛哥在电脑面前坐久了,想站起来看看窗外的小山坡,于是就想出了这个问题:
给定一个大小为n的数组a,序号从1开始,
计算:
max{ R - L | 1 <= L <= R <= n, a[L] == a[R], 对于所有i (L <= i <= R), 满足a[i] >= a[L] }.
也就是找到两个坐标,这两个坐标的值相等,并且他们之间的值都大于等于这两个坐标上的值.
这两个坐标相减最大能是多少.
用线段树存区间最小值。
然后用map存某个数上一次出现的位置。
扫一遍输入数据,如果发现一个以前出现过的数,就用线段树检测区间最小值是否大于等于这个值。
如果是,则符合题意。
如果否,则将该数的上一个位置更新为此位置。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t[8000050];
ll cnt=0;
ll a[2000100];
ll n;
map <ll,ll> m;
void pushup(ll rt)
{
t[rt]=min(t[rt<<1],t[rt<<1|1]);
}
void build(ll l=1,ll r=n,ll rt=1){
if(l==r){
cin>>t[rt];
a[++cnt]=t[rt];
return;
}
ll mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushup(rt);
}
ll query(ll ql,ll qr,ll l=1,ll r=n,ll rt=1)
{
if(ql<=l&&r<=qr){
return t[rt];
}
ll mid=(l+r)>>1;
ll ans=2e9;
if(mid>=ql){
ans=min(query(ql,qr,l,mid,rt<<1),ans);
}
if(mid<qr){
ans=min(query(ql,qr,mid+1,r,rt<<1|1),ans);
}
return ans;
}
int main()
{
ll ans=0;
cin>>n;
for(ll i=0;i<=4*n;i++)
t[i] = 1e9+10;
build();
for(ll i=1;i<=n;i++){
if(m[a[i]]==0){
m[a[i]]=i;
}else{
if(query(m[a[i]],i)>=a[i]){
ans=max(ans,i-m[a[i]]);
}else{
m[a[i]]=i;
}
}
}
cout<<ans;
return 0;
}