传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3196
题意:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
思路:窒息的操作
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
const int maxn = 5e4 + 1000;
inline void read(int &x){x = 0;char p = getchar();while(!(p <= '9' && p >= '0'))p = getchar();while(p <= '9' && p >= '0')x *= 10, x += p - 48, p = getchar();}
int d[maxn], m, n, p, s, t, v;
typedef vector<int>vec;
vec a[maxn];
inline void ins(vec&a, int v){ a.insert(lower_bound(a.begin(), a.end(), v), v);}
inline void del(vec&a, int v){ a.erase(lower_bound(a.begin(), a.end(), v));}
inline void ins(int i, int v){ for(; i <= n; i += i & -i) ins(a[i], v);}
inline void del(int i, int v){ for(; i <= n; i += i & -i)del(a[i], v);}
inline int ask(vec&a, int v) {return lower_bound(a.begin(), a.end(), v) - a.begin();}
inline int ask(int v, int s, int t)
{
int k = 1;
for(; s; s ^= s & -s)k -= ask(a[s], v);
for(; t; t ^= t & -t)k += ask(a[t], v);
return k;
}
inline int cal(int v, int s, int t)
{
int l = 0, r = 1e8;
while(l ^ r)
{
int j = l + r + 1 >> 1;
v >= ask(j, s, t) ? l = j : r = j - 1;
}
return l;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) read(d[i]);
for(int i = 1; i <= n; ++i) ins(i, d[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d", &p, &s, &t);
if(p == 3)
{
del(s, d[s]), ins(s, d[s] = t);///修改某一位置上的数值;
continue;
}
int ans=0;
--s, scanf("%d", &v);
if(p == 1) ans=ask(v, s, t);///查询 x在区间内的排名;
if(p == 2) ans=cal(v, s, t);///查询区间内排名为 k 的值;
///查询 x x x 在区间内的前趋(前趋定义为小于 x,且最大的数);
if(p == 5) ans=cal(ask(v + 1, s, t), s, t);
///查询 x x x 在区间内的后继(后继定义为大于 x,且最小的数)。
printf("%d\n",ans);
}
return 0;
}