洛谷题面链接

很早就过了,太久没打了,原本是在noip前用来练emacs的手感的。

noip炸了,就滚回来更博客了(安排的计数任务刷不动,学不会容斥,打发时间。。。)

众所周知,splay是个好算法,有着优秀的时间复杂度和更加优(巨)秀(大)的常数,而且我们得写双旋的splay,否则你在luogu得T飞。

我对平衡树的理解也不深,也只是会使用而已,浅谈啊什么的还是写不出来,我就分析一下每个操作需要注意的吧。

1.insert(x):

由于x的范围巨大,你需要用编号表示每个点,每个编号记一个权值

2.delete(x):

分多种情况:

1.只有x一个点,直接删

2.x只有左儿子,把根定为x的左儿子

3.x只有右儿子,同理

4.左右儿子都有,取前驱/后继(假设为y)旋到根节点,此时x节点只有右儿子(想一想为什么),然后直接将y的右儿子定为x的右儿子。

3.findx(x):

由于这个询问,你需要把所有权值相同的点都合并成一个点。

4~6

真没什么细节了!

splay代码:

#include<cstdio>
int n,size[100001],rt,id,v[100001],ch[100001][2],f[100001],cnt[100001];
void update(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];}
void move(int x,int &k)
{
int fa=f[x],faa=f[fa],tmp=(ch[fa][1]==x);
if(fa==k)k=x;else ch[faa][ch[faa][1]==fa]=x;
ch[fa][tmp]=ch[x][tmp^1];f[ch[x][tmp^1]]=fa;
ch[x][tmp^1]=fa;f[fa]=x;f[x]=faa;
update(fa),update(x);
}
void splay(int x,int &k)
{
while(x!=k)
{
int y=f[x],z=f[y];
if(y!=k)
{
if((ch[z][0]==y)^(ch[y][0]==x))move(y,k);
else move(x,k);
}
move(x,k);
}
}
void add(int x)
{
if(!rt){size[++id]=1,v[id]=x,rt=id,cnt[id]=1;return ;}
int now=rt;
while(1)
{
if(x==v[now]){cnt[now]++;update(now);splay(now,rt);return ;}
else if(x<v[now])
{
if(!ch[now][0])
{
v[++id]=x;ch[now][0]=id;size[id]=1;cnt[id]=1;
f[id]=now;update(now);break;
}
now=ch[now][0];
}
else
{
if(!ch[now][1])
{
v[++id]=x;ch[now][1]=id;size[id]=1;cnt[id]=1;
f[id]=now;update(now);break;
}
now=ch[now][1];
}
}
splay(id,rt);
}
int findS(int k,int x)
{
if(v[k]==x)return k;
if(v[k]>x)return findS(ch[k][0],x);
if(v[k]<x)return findS(ch[k][1],x);
}
int pre()
{
int x=ch[rt][0];
while(ch[x][1])x=ch[x][1];
return x;
}
int nxt()
{
int x=ch[rt][1];
while(ch[x][0])x=ch[x][0];
return x;
}
int findx(int k,int x)
{
if(!k)return 1;
if(v[k]>x)return findx(ch[k][0],x);
if(v[k]<x)return size[ch[k][0]]+cnt[k]+findx(ch[k][1],x);
if(v[k]==x){int d=size[ch[k][0]];splay(k,rt);return d+1;}
}
void del(int x)
{
int now=findS(rt,x);
splay(now,rt);if(cnt[now]>1){cnt[now]--;return ;}
if(!ch[now][0]&&!ch[now][1]){size[now]=cnt[now]=v[now]=0;rt=0;return ;}
if(ch[now][0]&&!ch[now][1]){int y=ch[now][0];ch[now][0]=f[y]=v[now]=cnt[now]=size[now]=0;rt=y;return ;}
if(!ch[now][0]&&ch[now][1]){int y=ch[now][1];ch[now][1]=f[y]=v[now]=cnt[now]=size[now]=0;rt=y;return ;}
int y=pre(),z=ch[now][1];splay(y,rt);f[z]=y;ch[y][1]=z;update(y);
}
int find(int k,int x)
{
if(x<=size[ch[k][0]])return find(ch[k][0],x);
if(x>size[ch[k][0]]&&x<=size[ch[k][0]]+cnt[k])return v[k];
return find(ch[k][1],x-size[ch[k][0]]-cnt[k]);
}
int main()
{
scanf("%d",&n);
for(int i=1,op,x,y;i<=n;i++)
{
scanf("%d",&op);
if(op==1)scanf("%d",&x),add(x);
if(op==2)scanf("%d",&x),del(x);
if(op==3)scanf("%d",&x),printf("%d\n",findx(rt,x));
if(op==4)scanf("%d",&x),printf("%d\n",find(rt,x));
if(op==5)scanf("%d",&x),add(x),printf("%d\n",v[pre()]),del(x);
if(op==6)scanf("%d",&x),add(x),printf("%d\n",v[nxt()]),del(x);
}
}

要知道线段树也能写这个题,权值线段树就好啦

先离散化,对于每个区间记一下该区间内有多少个数就行了,然后所有操作都可以支持了

代码:

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
#define mid ((s[x].l+s[x].r)>>1)
map<int,int>mp;
int n,w[100001],a[100001],b[100001],q[100001],tot,ans1,ans2,ans3;
struct oo{int l,r,v,mx,mn;}s[400001];
void build(int x,int l,int r)
{
s[x].l=l,s[x].r=r,s[x].mn=1e9;
if(l==r)return ;
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
}
void update(int x)
{
s[x].v=s[x<<1].v+s[x<<1|1].v;
s[x].mx=max(s[x<<1].mx,s[x<<1|1].mx);
s[x].mn=min(s[x<<1].mn,s[x<<1|1].mn);
}
void change(int x,int l,int v)
{
if(s[x].l==s[x].r)
{
s[x].v+=v;
if(s[x].v)s[x].mx=s[x].mn=l;
else s[x].mx=0,s[x].mn=1e9;
return ;
}
if(l<=mid)change(x<<1,l,v);
else change(x<<1|1,l,v);
update(x);
}
void get(int x,int l,int r)
{
if(l>r)return ;
if(l<=s[x].l&&r>=s[x].r)
{
ans1+=s[x].v,ans2=max(ans2,s[x].mx),ans3=min(ans3,s[x].mn);
return ;
}
if(l<=mid)get(x<<1,l,r);
if(r>mid)get(x<<1|1,l,r);
}
int ask(int x,int l)
{
if(s[x].l==s[x].r)return s[x].l;
if(l<=s[x<<1].v)return ask(x<<1,l);
else return ask(x<<1|1,l-s[x<<1].v);
}
int main()
{
scanf("%d",&n);int now=0;
for(int i=1;i<=n;i++){scanf("%d%d",&a[i],&b[i]);if(a[i]!=4)w[++now]=b[i];}
sort(w+1,w+now+1);
for(int i=1;i<=now;i++)if(!mp[w[i]])mp[w[i]]=++tot,q[tot]=w[i];
for(int i=1;i<=n;i++)if(a[i]!=4)b[i]=mp[b[i]];
build(1,1,tot);
for(int i=1;i<=n;i++)
{
if(a[i]==1)change(1,b[i],1);
if(a[i]==2)change(1,b[i],-1);
if(a[i]==3)ans1=ans2=0,ans3=1e9,get(1,1,b[i]-1),printf("%d\n",ans1+1);
if(a[i]==4)printf("%d\n",q[ask(1,b[i])]);
if(a[i]==5)ans1=ans2=0,ans3=1e9,get(1,1,b[i]-1),printf("%d\n",q[ans2]);
if(a[i]==6)ans1=ans2=0,ans3=1e9,get(1,b[i]+1,tot),printf("%d\n",q[ans3]);
}
}

BZOJ3224普通平衡树的更多相关文章

  1. [BZOJ3224]普通平衡树(旋转treap,STL-vector)

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 20328  Solved: 8979[Submit][St ...

  2. [bzoj3224]普通平衡树/3223文艺平衡树

    这是一道很普通的题.. 最近花了很多时间来想要去干什么,感觉自己还是太拿衣服 做这道题是因为偶尔看到了lavender的blog和她的bzoj早期AC记录,就被题目深深地吸引到了,原因有二: 自己sp ...

  3. BZOJ3224普通平衡树【Splay】

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 11751  Solved: 5013 Descriptio ...

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

    Problem 普通平衡树 Solution 本题是裸的二叉平衡树.有很多种方法可以实现.这里打的是替罪羊树模板. 此题极其恶心. 前驱后继模块需要利用到rank模块来换一种思路求. 很多细节的地方容 ...

  5. [转载]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)

    转载自ZZH大佬,原文:http://www.cnblogs.com/LadyLex/p/7182491.html 今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和t ...

  6. [您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)

    今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我 ...

  7. bzoj3224 普通平衡树(c++vector)

    Tyvj 1728 普通平衡树 2014年8月23日6,4365 Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有 ...

  8. BZOJ3224普通平衡树——非旋转treap

    题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...

  9. BZOJ3224普通平衡树——旋转treap

    题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...

随机推荐

  1. rac_udev建立磁盘方式安装grid时不识别磁盘

    原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明下面出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlo ...

  2. 火狐浏览器使用firebug获取xpath和css path

    工作中,常常会用到网页元素的定位方式,常用的有xpath和css path两种定位方式. 现在简单介绍如何使用工具自动生成元素的定位字符串. 首先介绍在火狐浏览器上使用FireBug及其扩展FireP ...

  3. 使用单例模式设计PDO数据操作类

    <?php /** * MyPDO * @author LHL <506698615@qq.com> * @date 2016.04.20 */ class MyPDO{ prote ...

  4. Ace(二)Demo示例

    Client: #include "ace/Log_Msg.h" #include "ace/OS.h" #include "ace/Service_ ...

  5. Emscripten实现把C/C++文件转成wasm,wast(wasm的可读形式),llvm字节码(bc格式),ll格式(llvm字节码的可读形式)并执行wasm

    <一>˙转换 Emscripten实现把C/C++文件转成wasm,wast(wasm的可读形式),llvm字节码(bc格式),ll格式(llvm字节码的可读形式)的步骤: 最新版本的Em ...

  6. 最小点覆盖 hdu--1054

    点击打开题目链接 最小点覆盖=最大二分匹配的 (单向图) ; 最小点覆盖=最大二分匹配的一半 (双向图) ; 证明 所以我们只需求最大匹配,用 匈牙利算法 求出最大匹配,除以二得到答案 具体算法都已经 ...

  7. hdu-5749 Colmerauer(单调栈)

    题目链接: Colmerauer Time Limit: 10000/5000 MS (Java/Others)     Memory Limit: 131072/131072 K (Java/Oth ...

  8. [LeetCode] Longest Valid Parentheses -- 挂动态规划羊头卖stack的狗肉

    (Version 1.3) 这题在LeetCode上的标签比较有欺骗性,虽然标签写着有DP,但是实际上根本不需要使用动态规划,相反的,使用动态规划反而会在LeetCode OJ上面超时.这题正确的做法 ...

  9. android jni下c文件怎么输出logcat

    #include <android/log.h> #define LOG_TAG "clog"#define LOGD(...) __android_log_print ...

  10. 一种C#开发ActiveX的思路

    由于某些原因,不得不在C#下开发ActiveX插件,而这会带来很多问题,主要有无法在线安装.无法自动更新.由于本人水平有些,这两个问题不一定是这样,如果有大侠知道C#下开发ActiveX插件可实现在线 ...