正题

题目链接:http://www.ybtoj.com.cn/problem/652


题目大意

定义一个元素为一个有序集合包含两个元素\(C=\{A,B\}\)

集合\(C=\{A,B\}\)的大小以\(A\)为第一关键字,\(B\)为第二关键字比较大小。

开始有两个元素\(S=\{S,S\},T=\{T,T\}\)且\(S<T\)。

然后\(n\)次加入一个新的由两个之前的元素依次组成的新元素,求出现过的元素小于等于它的有多少个。

\(1\leq n\leq 5\times 10^4\)


解题思路

如果递归比较是\(O(n)\)的显然不行,但是我们比较新的元素和旧的元素大小的时候如果我们可以知道以前元素的大小关系就可以快速比较(因为新的元素由旧的元素组成)

所以相当于我们要动态维护大小关系,因为要插入好像只能用平衡树。

然后要在树上查询两个点的大小关系,因为你要在平衡树上边移动边查询,所以不能用查询的时候结构会改变的平衡树(\(Splay\)之类的),正解是替罪羊的,反正这里用了\(Treap\)。

比较大小的时候直接在\(Treap\)上暴力跳找\(LCA\)就好了,深度是\(log\)级别的,然后不能动态维护深度所以有点麻烦

时间复杂度\(O(n\log^2 n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=51000;
int n,qfn,tot,a[N],b[N],p[N],v[N];
int t[N][2],siz[N],cnt[N],dat[N],fa[N];
int cmp(int x,int y){
++qfn;
if(x==y)return 2;
while(x){
if(fa[x]==y)
return t[y][0]==x;
v[x]=qfn;
x=fa[x];
}
while(y){
if(v[fa[y]]==qfn)
return t[fa[y]][1]==y;
y=fa[y];
}
return 0;
}
int cap(int x,int y){
int tmp=cmp(a[x],a[y]);
if(tmp!=2)return tmp;
return cmp(b[x],b[y]);
}
void PushUp(int x){
siz[x]=siz[t[x][0]]+siz[t[x][1]]+cnt[x];
return;
}
void zig(int &x){
int y=t[x][0];
t[x][0]=t[y][1];fa[t[y][1]]=x;
t[y][1]=x;fa[y]=fa[x];fa[x]=y;x=y;
PushUp(t[x][1]);PushUp(x);return;
}
void zag(int &x){
int y=t[x][1];
t[x][1]=t[y][0];fa[t[y][0]]=x;
t[y][0]=x;fa[y]=fa[x];fa[x]=y;x=y;
PushUp(t[x][0]);PushUp(x);return;
}
void Insert(int &x,int pos){
if(!x){
x=++tot;p[pos]=x;
a[tot]=a[pos];
b[tot]=b[pos];
cnt[x]=siz[x]=1;
dat[x]=rand();return;
}
int tmp=cap(pos,x),sum=0;
if(tmp==2){
p[pos]=x;cnt[x]++;
PushUp(x);return;
}
else if(tmp){
Insert(t[x][0],pos);fa[t[x][0]]=x;
if(dat[t[x][0]]>dat[x])zig(x);
}
else{
Insert(t[x][1],pos);fa[t[x][1]]=x;
if(dat[t[x][1]]>dat[x])zag(x);
}
PushUp(x);return;
}
int Query(int x){
int ans=siz[t[x][0]]+cnt[x];
while(x){
if(t[fa[x]][0]!=x)
ans+=siz[t[fa[x]][0]]+cnt[fa[x]];
x=fa[x];
}
return ans;
}
int main()
{
// freopen("comparison.in","r",stdin);
// freopen("comparison.out","w",stdout);
srand(19260817);
scanf("%d",&n);n++;
t[1][1]=n+1;
p[1]=1;a[1]=b[1]=1;
p[n+1]=n+1;a[n+1]=b[n+1]=n+1;
cnt[1]=cnt[n+1]=1;
fa[n+1]=tot=1;
PushUp(n+1);PushUp(1);
int rt=1;
for(int i=2;i<=n;i++){
scanf("%d%d",&a[i],&b[i]);
a[i]++;b[i]++;
a[i]=p[a[i]];b[i]=p[b[i]];
Insert(rt,i);
printf("%d\n",Query(p[i]));
}
return 0;
}

YbtOJ#652-集合比较【Treap】的更多相关文章

  1. 平衡树及笛卡尔树讲解(旋转treap,非旋转treap,splay,替罪羊树及可持久化)

    在刷了许多道平衡树的题之后,对平衡树有了较为深入的理解,在这里和大家分享一下,希望对大家学习平衡树能有帮助. 平衡树有好多种,比如treap,splay,红黑树,STL中的set.在这里只介绍几种常用 ...

  2. 15天玩转redis —— 第六篇 有序集合类型

    今天我们说一下Redis中最后一个数据类型 “有序集合类型”,回首之前学过的几个数据结构,不知道你会不会由衷感叹,开源的世界真好,写这 些代码的好心人真的要一生平安哈,不管我们想没想的到的东西,在这个 ...

  3. Treap入门(转自NOCOW)

    Treap 来自NOCOW Treap,就是有另一个随机数满足堆的性质的二叉搜索树,其结构相当于以随机顺序插入的二叉搜索树.其基本操作的期望复杂度为O(log n). 其特点是实现简单,效率高于伸展树 ...

  4. Treap和名次树

    Treap名字的来源:Tree+Heap,正如名字一样,就是一颗简单的BST,一坨堆的合体.BST的不平衡的根本原因在于基于左<=根<=右的模式吃单调序列时候会无脑成长链,而Treap则添 ...

  5. Java 集合系列 12 TreeMap

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  6. SPOJ 3273 - Order statistic set , Treap

    点击打开链接 题意: 集合S支持一下四种操作:   INSERT(S,x) :   假设S中没有x,则插入x DELETE(S,x):  假设S中有x,则删除x K-TH(S):           ...

  7. bzoj 3545&&3551: [ONTAK2010]Peaks &&加强版 平衡树&&并查集合并树&&主席树

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Stat ...

  8. bzoj1208 [HNOI2004]宠物收养所(STL,Treap)

    1208: [HNOI2004]宠物收养所 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5956  Solved: 2317[Submit][Sta ...

  9. bzoj1588 [HNOI2002]营业额统计(Treap)

    1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 11485  Solved: 4062[Submit][Sta ...

随机推荐

  1. 【spring】spring 核心注解

    注解具体分类如下: 1.模式注解 @Repository             数据仓储模式注解 @Component            通用组件模式注解 @Service            ...

  2. C# Monitor.Wait() 源码追踪 (转载)

    source: 释放对象上的锁并阻止当前线程,直到它重新获取该锁. 如果已用指定的超时时间间隔,则线程进入就绪队列. 可以在等待之前退出同步上下文的同步域,随后重新获取该域. [SecuritySaf ...

  3. 映射Map、队列Queue、优先级队列PriorityQueue

    映射Map 将对象映射到其他对象的能力是解决编程问题的有效方法.例如,考虑一个程序,它被用来检查 Java 的 Random 类的随机性.理想情况下, Random 会产生完美的数字分布,但为了测试这 ...

  4. java8 lambda表达式和函数式编程

    什么是函数式接口(Functional Interface) 其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法 (可以有def ...

  5. MongoDB学习笔记二- Mongoose

    MongoDB学习笔记二 Mongoose Mongoose 简介 之前我们都是通过shell来完成对数据库的各种操作, 在开发中大部分时候我们都需要通过程序来完成对数据库的操作 而Mongoose就 ...

  6. linux系统下深度学习环境搭建和使用

    作为一个AI工程师,对Linux的一些技能的掌握也能从一定层面反应工程师的资深水平. 要求1:基于SSH的远程访问(本篇文章) 能用一台笔记本电脑,远程登陆一台linux服务器 能随时使用笔记本电脑启 ...

  7. TCP模拟QQ聊天功能

    需求: 模拟qq聊天功能:实现客户端与服务器(一对一)的聊天功能,客户端首先发起聊天,输入的内容在服务器端和客户端显示,然后服务器端也可以输入信息,同样信息在客户端和服务端显示. 提示: 客户端 1) ...

  8. go进阶--测试

    目录 1.单元测试 1.1项目结构 1.2 源代码文件 1.3 单元测试 1.4 执行测试 1.5 单元测试总结 2.性能测试 2.1 项目结构 2.2 源码文件 2.3 测试文件 2.4 执行测试 ...

  9. 正整数a、b、c、d满足ab=cd,则a+b+c+d必定为合数。

    正整数a.b.c.d满足ab=cd,则a+b+c+d必定为合数. 证法一:记s=a+b+c+d.如果四个数全为1,s=4,显然是合数.考虑四个数非全1的情形,由对称性,不妨令a>1. 设p是a的 ...

  10. win+R 中的命令

    cmd------CMD命令提示符 MSConfig------系统配置实用程序 regedit------注册表编辑器 notepad------打开记事本 calc------启动计算器 msts ...