[TYVJ1728/BZOJ3224]普通平衡树-替罪羊树

Problem 普通平衡树

Solution

本题是裸的二叉平衡树。有很多种方法可以实现。这里打的是替罪羊树模板。 
此题极其恶心。 
前驱后继模块需要利用到rank模块来换一种思路求。 
很多细节的地方容易炸。我拿数据调了很久才A。 
(delt()删除模块其实是不需要重建的,不影响时间复杂度) 
替罪羊树具体详见此篇知乎:替罪羊树

AC Code

  1 #include "iostream"
  2 #include "cstdio"
  3 #define alpha 0.7
  4 using namespace std;
  5 struct ScapeGoatTree{
  6     int lc,rc,n,w,s,fa;
  7 }a[100010];
  8 struct REbuild{
  9     int n,w;
 10 }d[100010];
 11 void rebuild(int p);
 12 int tot=1,tott=0,top=0,h[100010],n,T,X,root;
 13 int check(int p){
 14     if(a[p].w==0)return 0;
 15     if ((a[a[p].lc].s+a[a[p].lc].w>=double(alpha*(a[p].w+a[p].s)))||
 16         (a[a[p].rc].s+a[a[p].rc].w>=double(alpha*(a[p].w+a[p].s))))return 1;
 17     return 0;
 18 }
 19 int getN(int x){
 20     int now=root;
 21     while(a[now].n!=x&&a[now].s!=0){
 22         if(a[now].n>=x)now=a[now].lc;
 23         else now=a[now].rc;
 24     }
 25     return now;
 26 }
 27 void insr(int x,bool rb){
 28     if(root==0){
 29         root=1;
 30         a[1].n=x;
 31         a[1].w++;
 32         return;
 33     }
 34     int now=root;
 35     while(a[now].s!=0){
 36         if(x==a[now].n){
 37             a[now].w++;
 38             return;
 39         }
 40         if(x>a[now].n&&a[now].rc==0)break;
 41         if(x<a[now].n&&a[now].lc==0)break;
 42         a[now].s++;
 43         if(x>a[now].n)now=a[now].rc;
 44         else if(x<a[now].n)now=a[now].lc;
 45     }
 46
 47     if(x==a[now].n){
 48         a[now].w++;
 49         return;
 50     }
 51     a[now].s++;
 52     int tmp=now;
 53     if(x>a[now].n)now=a[now].rc=++tot;
 54     else if(x<a[now].n)now=a[now].lc=++tot;
 55     a[now].w++;
 56     a[now].n=x;
 57     if(tmp!=now)a[now].fa=tmp;
 58     int chk=0;
 59     while(now!=root){
 60         now=a[now].fa;
 61         if(check(now))chk=now;
 62     }
 63     if(rb)rebuild(chk);
 64 }
 65 int getnewp(){
 66     if(top>0){
 67         top--;
 68         return h[top+1];
 69     }
 70     else return ++tot;
 71 }
 72 void dfs(int p){
 73     h[++top]=p;
 74     if(a[p].lc!=0)dfs(a[p].lc);
 75     if(a[p].w!=0)d[++tott].n=a[p].n,
 76     d[tott].w=a[p].w;
 77     a[p].s=0;
 78     if(a[p].rc!=0)dfs(a[p].rc);
 79 }
 80 void make(int l,int r,int p,int fa){
 81     int mid=(l+r)/2;
 82     a[p].fa=fa;
 83     a[p].w=d[mid].w;
 84     a[p].n=d[mid].n;
 85     if(mid-1>=l)a[p].lc=getnewp(),make(l,mid-1,a[p].lc,p);else a[p].lc=0;
 86     if(mid+1<=r)a[p].rc=getnewp(),make(mid+1,r,a[p].rc,p);else a[p].rc=0;
 87     a[p].s=a[a[p].lc].w+a[a[p].lc].s+a[a[p].rc].w+a[a[p].rc].s;
 88 }
 89 void rebuild(int p){
 90     if(p==0)return;
 91     tott=0;
 92     dfs(p);
 93     int now=getnewp();
 94     a[now].fa=a[p].fa;
 95     if(p==root)root=now;
 96     int mid=(1+tott)/2;
 97     if(d[mid].n>a[a[p].fa].n)a[a[p].fa].rc=now;
 98     else a[a[p].fa].lc=now;
 99     make(1,tott,now,a[p].fa);
100 }
101 void delt(int p,bool rb){
102     a[p].w--;
103     int chk=0;
104     while(p!=root){
105         p=a[p].fa;
106         a[p].s--;
107         if(check(p))chk=p;
108     }
109 //  if(rb)rebuild(chk);
110 }
111 int XgetRk(int x);
112 int RkgetX(int x);
113 int suc(int x){
114     insr(x+1,0);
115     int tmp=XgetRk(x+1),nx=getN(x+1);
116     delt(nx,0);
117     return RkgetX(tmp);
118 }
119 int pre(int x){
120     insr(x,0);
121     int tmp=XgetRk(x);
122     delt(getN(x),0);
123     return RkgetX(tmp-1);
124 }
125 int XgetRk(int x){
126     int p=getN(x),ans;
127     ans=a[a[p].lc].s+a[a[p].lc].w;
128     while(p!=root){
129         if(a[a[p].fa].rc==p)ans+=a[a[a[p].fa].lc].s+a[a[a[p].fa].lc].w+a[a[p].fa].w;
130         p=a[p].fa;
131     }
132     return ans+1;
133 }
134 int RkgetX(int x){
135     int now=root;
136     while(true){
137         int lcS=a[a[now].lc].s+a[a[now].lc].w;
138         if(x<=lcS)now=a[now].lc;
139         else if(x>lcS&&x<=a[now].w+lcS)return a[now].n;
140         else x-=lcS+a[now].w,now=a[now].rc;
141         if(x==0)return a[now].fa;
142     }
143 }
144 int main(){
145     scanf("%d",&n);
146     for(int i=1;i<=n;i++){
147         if(i%1000==0){
148             int ttott;
149             ttott++;
150         }
151         scanf("%d%d",&T,&X);
152         if(T==1)insr(X,1);
153         else if(T==2)delt(getN(X),1);
154         else if(T==3)printf("%d\n",XgetRk(X));
155         else if(T==4)printf("%d\n",RkgetX(X));
156         else if(T==5)printf("%d\n",pre(X));
157         else if(T==6)printf("%d\n",suc(X));
158     }
159 }
时间: 2024-08-05 06:50:27

[TYVJ1728/BZOJ3224]普通平衡树-替罪羊树的相关文章

[luogu3369]普通平衡树(替罪羊树模板)

解题关键:由于需要根据平衡进行重建,所以不能进行去重,否则无法保证平衡性. #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> #include<vector> using namespace std; typedef long long ll; const d

Bzoj3224 / Tyvj 1728 普通替罪羊树

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 12015  Solved: 5136 Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为小于x,且最大的数)6. 求x的后继(后继定义为大于x,且最小的数) Input 第一行为n,

替罪羊树(重量平衡树)总结及板子

没事干写个板子来玩一玩...平衡树的板子,上一篇写的 splay 的题解,这一篇来搞点别的.其实就我自己来说,并不太喜欢 splay ,各种旋转什么的,扭扭捏捏一点都不爽,那怎么办咧,于是学了这么个东西---替罪羊树,不平衡就重构嘛,简单粗暴,写起来也方便. 替罪羊树的主要思想就是将不平衡的树压成一个序列,然后暴力重构成一颗平衡的树. 这里的平衡指的是:对于某个 0.5<=alpha<=1 满足 size( lson(x) )<=alpha*size(x) 并且 size( rson(x

替罪羊树 ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) 闲的没事,把各种平衡树都写写 比较比较... 下面是替罪羊树 #include <cstdio> #include <vector> #define Max_ 100010 #define Inline __attri\ bute__( ( optimize( "-O2" ) ) ) Inline void read (int &now) { register char w

替罪羊树模版 普通平衡树

替罪羊树,代码贼长,我哭了... #include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<vector> using namespace std; const int maxn = 1e5+5; const double alpha = 0.75; struct node{ int l,r,val; int size,fact; //

斜堆,非旋转treap,替罪羊树

一.斜堆 斜堆是一种可以合并的堆 节点信息: struct Node { int v; Node *ch[2]; }; 主要利用merge函数 Node *merge(Node *x, Node *y) { if(!x) return y; if(!y) return x; if(x->v < y->v) swap(x, y); x->ch[1] = merge(x->ch[1], y); return swap(x->ch[0], x->ch[1]), x; }

BZOJ 3065 带插入区间K小值 替罪羊树套线段树

题目大意:带插入,单点修改的区间k小值在线查询. 思路:本年度做过最酸爽的题. 树套树的本质是一个外层不会动的树来套一个内层会动(或不会动)的树.两个树的时间复杂度相乘也就是差不多O(nlog^2n)左右.但是众所周知,高级数据结构经常会伴有庞大的常数,所以一般来说树套树的常数也不会小到哪去.所以在做这种题的时候先不要考虑常数的问题... 为什么要用替罪羊树呢?因为一般的平衡树都是会动的,这就很难办了.外层的树动了之后,内层的树肯定也是会动的.很显然,一般的二叉平衡树会经常会旋转,这样在动外层的

[BZOJ3065]带插入区间K小值 解题报告 替罪羊树+值域线段树

刚了一天的题终于切掉了,数据结构题的代码真**难调,这是我做过的第一道树套树题,做完后感觉对树套树都有阴影了......下面写一下做题记录. Portal Gun:[BZOJ3065]带插入区间k小值. 这道题的题面其实都提醒怎么做了,维护区间k小值用值域线段树,但要维护一个插入操作,树状数组套主席树也用不了,那么这道题还剩下平衡树可以搞,那就上平衡树吧. 我这里的做法,因为要维护序列的顺序,所以我这里用到替罪羊树套值域线段树:我们在替罪羊树的每个节点都套一颗值域线段树,记录以该节点为根的子树的

[数据结构]替罪羊树简介

替罪羊树是不通过旋转而是重构的一种平衡树.当某一棵子树的节点总数超过其父节点的一定时,就进行重构操作. 目录 节点定义 重构操作 插入操作 删除操作 其他各种操作 完整代码&总结 [节点定义] 为了判断是否需要重构,所以需要加入cover(实际节点个数)域.这次直接加入可重操作,所以还需要增加一个size域.为了体现C++面向对象的思想(分明就是Java用多了),所以判断一个子树是否需用重构写成成员函数bad().(真开心,因为是重构,不需要那么多的father,终于可以轻松地删掉父节点指针)