[luogu3369][普通平衡树]

题目链接

思路

模板
只是有几个容易出错的地方
第45行容易忘记
第54行里面的cnt--和siz--容易忘记
第56行是根据id判断不是val
第60行siz--容易忘记
第64行是siz+1不是siz+cnt
第77行和82行等于的情况容易忽略

代码

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<ctime>
#define ls TR[cur].ch[0]
#define rs TR[cur].ch[1]
using namespace std;
typedef long long ll;
const int N = 100000 + 100,INF = 1e7 + 100;
ll read() {
   ll x = 0,f = 1;char c = getchar();
   while(c < '0' || c > '9') {
      if(c == '-') f = -1;
      c = getchar();
   }
   while(c >= '0' && c <= '9') {
      x = x * 10 + c - '0';
      c = getchar();
   }
   return x * f;
}
struct node {
   int ch[2],val,id,cnt,siz;
}TR[N];
void up(int cur) {
   TR[cur].siz = TR[ls].siz + TR[rs].siz + TR[cur].cnt;
}
void rotate(int &cur,int f) {
   int son = TR[cur].ch[f];
   TR[cur].ch[f] = TR[son].ch[f ^ 1];
   TR[son].ch[f ^ 1] = cur;
   up(cur);
   cur = son;
   up(cur);
}
int tot;
void insert(int &cur,int val) {
   if(!cur) {
      cur = ++tot;
      TR[cur].val = val;
      TR[cur].id = rand();
      TR[cur].cnt = TR[cur].siz = 1;
      return;
   }
   TR[cur].siz++;//!!
   if(TR[cur].val == val) { TR[cur].cnt++;return;}
   int d = val > TR[cur].val;
   insert(TR[cur].ch[d],val);
   if(TR[TR[cur].ch[d]].id < TR[cur].id) rotate(cur,d);
}
void del(int &cur,int val) {
   if(!cur) return;
   if(val == TR[cur].val) {
      if(TR[cur].cnt > 1) {TR[cur].cnt--;TR[cur].siz--; return;}
      if(!ls || !rs) {cur = ls + rs;return;}
      int d = TR[rs].id < TR[ls].id;
      rotate(cur,d);
      del(cur,val);
   }
   else TR[cur].siz--,del(TR[cur].ch[val > TR[cur].val],val);
}
int Rank(int cur,int val) {
   if(!cur) return 0;
   if(val == TR[cur].val) return TR[ls].siz + 1;
   if(val < TR[cur].val) return Rank(ls,val);
   return Rank(rs,val) + TR[ls].siz + TR[cur].cnt;
}
int kth(int cur,int now) {
   while(1) {
      if(TR[ls].siz >= now) cur = ls;
      else if(TR[ls].siz + TR[cur].cnt < now) now -=TR[ls].siz + TR[cur].cnt,cur = rs;
      else return TR[cur].val;
   }
}
int pred(int cur,int val) {
   if(!cur) return -INF;
   if(val <= TR[cur].val) return pred(ls,val);//!!!
   return max(pred(rs,val),TR[cur].val);
}
int nex(int cur,int val) {
   if(!cur) return INF;
   if(val >= TR[cur].val) return nex(rs,val);//!!!
   return min(nex(ls,val),TR[cur].val);
}
int main() {
   srand(time(0));
   int n = read();
   int rt = 0;
   while(n--) {
      int opt = read(),x = read();
      if(opt == 1) insert(rt,x);
      if(opt == 2) del(rt,x);
      if(opt == 3) printf("%d\n",Rank(rt,x));
      if(opt == 4) printf("%d\n",kth(rt,x));
      if(opt == 5) printf("%d\n",pred(rt,x));
      if(opt == 6) printf("%d\n",nex(rt,x));
   }

   return 0;
}

一言

记忆或会消失,但我的心会记着承诺。

全部评论

相关推荐

02-07 12:06
已编辑
华侨大学 测试开发
最近看到很多&nbsp;92&nbsp;的,甚至是硕士,开始往测开赛道卷,说实话有点看不懂。先把话说清楚,大厂里的测开,绝大多数时间干的还是测试的活,只是写点自动化脚本、维护测试平台、接接流水线,真正像开发一样做系统、做架构、做核心平台的测开少得可怜,基本都集中在核心提效组,而且人很少,外面进去的大概率轮不到你,我想真正干过人都清楚。很多人被洗脑了,以为测开也是开,和后端差不多,只是更简单、更轻松、还高薪。现实情况是,测开和开发的职业路径完全不一样。开发的核心是业务和系统能力,测开的核心是稳定性和覆盖率,前者是往上走,后者天花板非常明显。你可以见到很多开发转测开,但你很少见到干了几年测开还能顺利转回开发的。更现实一点说,92&nbsp;的高学历如果拿来做测开,大部分时间就是在做重复性很强的杂活,这种工作对个人能力的放大效应非常弱。三年下来,你和一个双非的,甚至本科的测开差距不会太大,但你和同龄的后端、平台开发差距会非常明显。这不是努不努力的问题,是赛道问题。所谓测开简单高薪,本质上是把极少数核心测开的上限,当成了整个岗位的常态来宣传。那些工资高、技术强的测开,本身就是开发水平,只是挂了个测开的名。普通人进去,99%&nbsp;做的都是项目兜底型工作,而不是你想象中的平台开发。测开不是不能做,但它绝对不是开发的平替,也不是性价比最优解。如果你是真的不想做开发,追求稳定,那测开没问题。但如果你只是觉得测开比后端容易,还能进大厂,那我劝你冷静一点,这只是在用短期安全感换长期天花板。有92的学历,如果你连测开这些重复性工作都能心甘情愿接受,那你把时间精力用在真正的开发、系统、业务深度上,回报大概率比卷测开要高得多。想清楚再下场,别被岗位名和话术带偏了,就算去个前端客户端也是随便占坑的,测开是一个坑位很少赛道,反而大面积学历下放,不用想也能知道会是什么结果,我想各位在JAVA那里已经看到了
小浪_Coding:工作只是谋生的手段 而不是相互比较和歧视
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务