BZOJ_3224 Tyvj 1728 普通平衡树 【离散化+权值线段树】

一 题面

  Tyvj 1728 普通平衡树

二 分析

  比较明显是可以用平衡二叉搜索树(splay)做的。

  用权值线段树做,前提就是要先离散化,因为权值线段树维护的值域信息。

  板子。

三 AC代码

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <fstream>
  5 
  6 using namespace std;
  7 #define lson rt<<1
  8 #define rson rt<<1|1
  9 
 10 const int MAXN = 1e5 + 15;
 11 int N, op[MAXN], opx[MAXN];
 12 struct Node
 13 {
 14     int id, x;
 15 }Data[MAXN];
 16 int A[MAXN];
 17 
 18 int segTree[MAXN<<2];
 19 
 20 bool Cmpx(const Node &a, const Node &b)
 21 {
 22     return a.x < b.x;
 23 }
 24 
 25 //p更新的位置,v=-1表示减,v=1表示加
 26 void Update(int p, int v, int rt, int l, int r)
 27 {
 28     segTree[rt] += v;
 29     if(l == r)  return;
 30     int mid = (l+r)>>1;
 31     if(p <= mid) Update(p, v, lson, l, mid);
 32     else    Update(p, v, rson, mid+1, r);
 33 }
 34 //第K小
 35 int Kth(int K, int rt, int l, int r)
 36 {
 37     if(l == r)
 38         return l;
 39     int mid = (l+r)>>1;
 40     if(segTree[lson] >= K)  
 41         return Kth(K, lson, l, mid);
 42     else
 43         return Kth(K-segTree[lson], rson, mid+1, r);
 44 }
 45 //数字v的排名
 46 //统计小于v的数的个数
 47 int Rank(int v, int rt, int l, int r)
 48 {
 49     if(r < v)
 50         return segTree[rt];
 51     int mid = (l+r)>>1, res = 0;
 52     res += Rank(v, lson, l, mid);
 53     //相当于mid+1 < v 那么左边可能还有
 54     if(mid < v-1)
 55         res += Rank(v, rson, mid+1, r);
 56     return res;
 57 }
 58 //找最右边的数
 59 int Findr(int rt, int l, int r)
 60 {
 61     if(l == r)
 62         return l;
 63     int mid = (l+r)>>1;
 64     if(segTree[rson])     return Findr(rson, mid + 1, r);
 65     return Findr(lson, l, mid);
 66 }
 67 //前驱
 68 int Pre(int v, int rt, int l, int r)
 69 {
 70     if(r < v)
 71     {
 72         if(segTree[rt])   return Findr(rt, l, r);
 73         return 0;
 74     }
 75     int mid = (l+r)>>1, res;
 76     //如果v > mid+1那么意味着mid+1或后面的数有可能是前驱
 77     if(mid < v-1 && segTree[rson] && (res=Pre(v,rson,mid+1,r)))
 78         return res;
 79     return Pre(v, lson, l, mid);
 80 }
 81 //找最左边的数
 82 int Findl(int rt, int l, int r)
 83 {
 84     if(l == r)
 85         return l;
 86     int mid = (l+r)>>1;
 87     if(segTree[lson])   return Findl(lson, l, mid);
 88     return Findl(rson, mid+1, r);
 89 }
 90 //后继
 91 int Nex(int v, int rt, int l, int r)
 92 {
 93     if(v < l)
 94     {
 95         if(segTree[rt]) return Findl(rt, l, r);
 96         return 0;
 97     }
 98     int mid = (l+r)>>1, res;
 99     //如果mid > v表示左子树的数可能是后继
100     if(v < mid && segTree[lson] && (res=Nex(v,lson,l,mid)))
101         return res;
102     return Nex(v, rson, mid + 1, r);
103 }
104 
105 int main()
106 {
107     //freopen("input.txt", "r", stdin);
108     scanf("%d", &N);
109     for(int i = 1; i <= N; i++)
110     {
111         scanf("%d %d", &op[i], &Data[i].x);
112         Data[i].id = i;
113     }
114     //离散化预处理
115     sort(Data  + 1, Data + N + 1, Cmpx);
116     int cnt = 1;
117     A[cnt] = Data[1].x;
118     opx[Data[1].id] = cnt;
119     for(int i = 2; i <= N; i++)
120     {
121         if(Data[i].x != Data[i - 1].x)
122         {
123             cnt++;
124         }
125         A[cnt] = Data[i].x;
126         opx[Data[i].id] = cnt;
127     }
128     //建树
129     memset(segTree, 0, sizeof(segTree) );
130     for(int i = 1; i <= N; i++)
131     {
132         switch(op[i])
133         {
134             case 1: Update(opx[i], 1, 1, 1, cnt);                   break;
135             case 2: Update(opx[i], -1, 1, 1, cnt);                  break;
136             case 3: printf("%d\n", Rank(opx[i], 1, 1, cnt)+1);      break;
137             //这里注意第K个数也离散化了!!!
138             case 4: printf("%d\n", A[ Kth(A[opx[i]], 1, 1, cnt)] ); break;
139             case 5: printf("%d\n", A[ Pre(opx[i], 1, 1, cnt)] );    break;
140             case 6: printf("%d\n", A[ Nex(opx[i], 1, 1, cnt)] );    break;
141         }
142     }
143 
144     return 0;
145 }
View Code

 

posted @ 2019-04-29 22:54  Dybala21  阅读(159)  评论(0编辑  收藏  举报