题目链接
https://nanti.jisuanke.com/t/49111
题意
n n n 个数, m m m 个操作,每个操作给3个数: l r t l \ r \ t l r t,让你输出这个区间满足个数超过 r − l + 1 t \frac{r-l+1}{t} tr−l+1的最大的数。
思路
查询区间满足一定条件数,首先想到主席树,根据原序列建立主席树(可持久化权值线段树),查询的时候,优先去右边找,右边找不到再去左边找,这样能保证找到的数最大.
代码
#include <bits/stdc++.h>
#define ft first
#define sd second
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<ll,string> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const int N=1e9;
int n,m;
struct node{
int l,r,sum;
}no[maxn*40];
int cnt,root[maxn],a[maxn];
void add(int l,int r,int pre,int &now,int x){
now=++cnt;
no[now]=no[pre];
++no[now].sum;
if(l==r)return;
int mid=(l+r)>>1;
if(x<=mid)add(l,mid,no[pre].l,no[now].l,x);
else add(mid+1,r,no[pre].r,no[now].r,x);
}
//主席树上二分找最右边满足要求的数,这个数肯定是最大的
int query(int l,int r,int pre,int now,int x){
if(l==r){//看该数是否>=x,不是就按题意返回-1
if(no[now].sum-no[pre].sum<x)return -1;
else return l;
}
int mid=(l+r)>>1,ans=-1;
int sumR=no[no[now].r].sum-no[no[pre].r].sum;
//先去右边找
if(sumR>=x)ans=query(mid+1,r,no[pre].r,no[now].r,x);
if(ans!=-1)return ans;
else {//右边没找到再去左边找
ans=query(l,mid,no[pre].l,no[now].l,x);
return ans;
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
add(1,N,root[i-1],root[i],a[i]);
}
while(m--){
int l,r,t;
scanf("%d%d%d",&l,&r,&t);
int x=(r-l+1)/t+1;//要求大于,那就向下取整加一
printf("%d\n",query(1,N,root[l-1],root[r],x));
}
return 0;
}