洛谷.3224.[HNOI2012]永无乡(Splay启发式合并)
查找排名为k的数用平衡树
合并时用启发式合并,把size小的树上的所有节点插入到size大的树中,每个节点最多需要O(logn)时间
并查集维护连通关系即可
O(nlogn*insert time)
据(主席)说按顺序插入能做到均摊O(1),中序遍历即可有序插入
1.并查集与平衡树是独立的!不要混用fa!并查集只起判断连通关系的作用
2.不需要记录root,Splay时到fa[x]=0即可,因为合并是在一棵树中插入
3.Splay中条件!
Update(18.10.2):Splay支持finger search,所以启发式合并是一个\(\log\)的。
Treap因为某种奇怪的性质所以启发式合并也是一个\(\log\)的。
set可能是。
#include<cstdio>
#include<cctype>
#include<algorithm>
#define gc() getchar()
const int N=1e5+5;
int n,m,ff[N],t[N],son[N][2],fa[N],sz[N];
inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
inline void Update(int rt)
{
sz[rt]=sz[son[rt][0]]+sz[son[rt][1]]+1;
}
void Rotate(int x)
{
int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
if(b) son[b][son[b][1]==a]=x;
// if(!a) printf("Warning:b:%d x:%d\n",b,x);
fa[x]=b, fa[a]=x, fa[son[x][r]]=a;
son[a][l]=son[x][r], son[x][r]=a;
Update(a), Update(x);
}
void Splay(int x)
{
while(fa[x])//相差不大,反而这样略快
{
int a=fa[x],b=fa[a];
if(b)//注意是fa[a]!
{//如果是a,那若这时fa[a]=0,fa[x]会变为0,再经一次Rotate(x)后会改变fa[x]即fa[0]的值
if((son[a][1]==x)^(son[b][1]==a)) Rotate(x);
else Rotate(a);
}
Rotate(x);
}
// for(int f;f=fa[x];Rotate(x))
// if(fa[f])
// ((son[f][1]==x)^(son[fa[f]][1]==f))?Rotate(x):Rotate(f);
}
void Insert(int k,int y)
{
while(son[k][t[y]>t[k]]) k=son[k][t[y]>t[k]];
fa[y]=k, son[k][t[y]>t[k]]=y, sz[y]=1;
++sz[k];
// printf("k:%d fa:%d\n",k,fa[k]);
Splay(k);
}
int Getf(int x)
{
return x==ff[x]?x:ff[x]=Getf(ff[x]);
}
void DFS(int tar,int y)
{
int l=son[y][0],r=son[y][1];//要清空节点信息,所以清空前要记录
son[y][0]=son[y][1]=fa[y]=/*sz[y]=*/0;
if(l) DFS(tar,l);
Insert(tar,y);
if(r) DFS(tar,r);
}
void Merge(int x,int y)
{
// int r1=Getf(x),r2=Getf(y);
if(x==y) return;
Splay(x),Splay(y);//保证复杂度
if(sz[x]<sz[y]) std::swap(x,y);
ff[y]=x;
DFS(x,y);
}
int Rank(int v,int x)
{
Splay(x);
if(v>sz[x]) return -1;
int k=x;
while(1)
{
if(sz[son[k][0]]+1>=v && sz[son[k][0]]<v) return k;
if(sz[son[k][0]]>=v) k=son[k][0];
else v-=sz[son[k][0]]+1,k=son[k][1];
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("3224.in","r",stdin);
#endif
n=read(),m=read();
for(int i=1;i<=n;++i) t[i]=read(),ff[i]=i,sz[i]=1;
int q,a,b;
char s[5];
while(m--) a=Getf(read()),b=Getf(read()),Merge(a,b);
q=read();
while(q--)
{
scanf("%s",s),a=Getf(read()),b=read();
if(s[0]=='Q') printf("%d\n",Rank(b,a));
else b=Getf(b),Merge(a,b);
}
return 0;
}
洛谷.3224.[HNOI2012]永无乡(Splay启发式合并)的更多相关文章
- BZOJ 2733: [HNOI2012]永无乡 [splay启发式合并]
2733: [HNOI2012]永无乡 题意:加边,询问一个连通块中k小值 终于写了一下splay启发式合并 本题直接splay上一个节点对应图上一个点就可以了 并查集维护连通性 合并的时候,把siz ...
- 【洛谷3224/BZOJ2733】[HNOI2012]永无乡 (Splay启发式合并)
题目: 洛谷3224 分析: 这题一看\(n\leq100000\)的范围就知道可以暴力地用\(O(nlogn)\)数据结构乱搞啊-- 每个联通块建一棵Splay树,查询就是Splay查询第k大的模板 ...
- 洛谷P3224 [HNOI2012]永无乡(线段树合并+并查集)
题目描述 永无乡包含 nnn 座岛,编号从 111 到 nnn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nnn 座岛排名,名次用 111 到 nnn 来表示.某些岛之间由巨大的桥连接, ...
- [BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)
Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...
- 洛谷 P3224 [HNOI2012]永无乡 解题报告
P3224 [HNOI2012]永无乡 题目描述 永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 ...
- 【BZOJ-2733】永无乡 Splay+启发式合并
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2048 Solved: 1078[Submit][Statu ...
- BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)
不难...treap + 启发式合并 + 并查集 搞搞就行了 --------------------------------------------------------------------- ...
- 洛谷 P3224 [HNOI2012]永无乡
题面 永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 \(1\) 到 \(n\) 来表示.某些岛 ...
- 【bzoj2733】[HNOI2012]永无乡 Treap启发式合并
题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...
随机推荐
- BackBone结合ASP.NET MVC实现页面路由操作
1. 问题的背景 什么是页面路由操作,就是通过浏览器地址栏的标记来实现页面内部的一些操作,这些操作具有异步性和持久性.应用场景主要有页面操作过程中的添加收藏夹的操作.后退操作等过程中能完全恢复界面. ...
- C++学习5-面向对象编程基础(构造函数、转换构造、静态数据成员、静态成员函数、友元)
知识点学习 类 const作用 C语言的const限定符的含义为"一个不能改变值的变量",C++的const限定符的含义为"一个有类型描述的常量": const ...
- 『PyTorch』第五弹_深入理解autograd_上:Variable属性方法
在PyTorch中计算图的特点可总结如下: autograd根据用户对variable的操作构建其计算图.对变量的操作抽象为Function. 对于那些不是任何函数(Function)的输出,由用户创 ...
- [ VB ] OrElse, AndAlso [ C# ] ||, && 运算符
条件演算子も当然のように C# と VB では記述方法が異なる.比較すると下表のようになる. VB C#OrElse ||AndAlso &&a ...
- 深入解析内存原理:DRAM的基本原理
前面我们知道了在一个简单的SRAM 芯片中进行读写操作的步骤了,然后我们来了解一下普通的DRAM 芯片的工作情况.DRAM 相对于SRAM 来说更加复杂,因为在DRAM存储数据的过程中需要对于存储的信 ...
- 使用Struts,实现简单的登录
一.新建项目Struts 1.右键 new————Web Project 2.点击项目——右键——myeclipse——add Struts Capabilities.....——选择struts2. ...
- Mac上安装stf
一,安装 STF的依赖比较多,如下: Node.js >= 0.12ADB properly set upRethinkDB >= 2.2GraphicsMagick (for resiz ...
- 获取修改value
val() 方法,获取和修改有value属性的元素,有value属性的元素有input.botton.select等.相当于JavaScript中的value. <!DOCTYPE html&g ...
- ireport 添加行自增序号
ireport 添加行自增序号 在ireport报表中加入行的自增序号方法: 添加一个变量,如变量名为 index: 设置变量类型为Integer,计算类型为count:变量表达式为$V{index} ...
- android修改默认输入法
方案一:adb命令设置?方案2:系统配置:方案3:调用系统API接口设置---------------------------adb shell cmdadb rootadb remountadb p ...