BZOJ 3196: Tyvj 1730 二逼平衡树 窒息的操作

传送门: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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值