题目:

洛谷3224

分析:

这题一看\(n\leq100000\)的范围就知道可以暴力地用\(O(nlogn)\)数据结构乱搞啊……

每个联通块建一棵Splay树,查询就是Splay查询第k大的模板,建桥的时候就把两个联通块的Splay进行“启发式合并”

本来以为启发式合并是什么高端的东西,tzh神犇给我说就是把小的推倒然后暴力插入到大的里面2333

初始我给每个岛都建了一棵Splay树,合并\(a\), \(b\)两岛 (\(size_a<size_b\)) 时将\(a\)树插入到\(b\)树中,然后删除\(a\)树。合并两联通块同理。注意由于除了并查集祖先的树,该联通块中其他的树都已经被删除,所以要用并查集辅助记录哪个岛(\(b\))“代表”这个联通块

建桥时一定要判断两个点是否已经在同一联通块内,合并空树会RE!!!

我SB啊因为这个调一下午

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std; namespace zyt
{
const int N = 100010;
int n, m, rank[N];
struct Splay
{
struct node
{
int val, id, size;
node *fa, *s[2];
node(node *const f, const int v, const int i):fa(f), val(v), id(i)
{
s[0] = s[1] = NULL;
size = 1;
}
}*head;
void update(node *rot)
{
rot->size = 1;
if (rot->s[0])
rot->size += rot->s[0]->size;
if (rot->s[1])
rot->size += rot->s[1]->size;
}
bool dir(const node *rot)
{
return rot == rot->fa->s[1];
}
void rotate(node *rot)
{
node *f = rot->fa, *ff = f->fa;
bool d = dir(rot);
rot->fa = ff;
if (ff)
ff->s[dir(f)] = rot;
else
head = rot;
f->s[d] = rot->s[!d];
if (rot->s[!d])
rot->s[!d]->fa = f;
f->fa = rot;
rot->s[!d] = f;
update(f);
update(rot);
}
void splay(node *rot, const node *goal = NULL)
{
while (rot && rot->fa != goal)
{
node *f = rot->fa, *ff = f->fa;
if (ff)
if (dir(rot) ^ dir(f))
rotate(rot), rotate(rot);
else
rotate(f), rotate(rot);
else
rotate(rot);
}
}
void insert(const int id, const int val)
{
node *rot = head;
if (rot == NULL)
head = new node(NULL, val, id);
else
{
while (1)
{
if (val < rot->val)
if (rot->s[0])
rot = rot->s[0];
else
{
rot->s[0] = new node(rot, val, id);
splay(rot->s[0]);
break;
}
else
if (rot->s[1])
rot = rot->s[1];
else
{
rot->s[1] = new node(rot, val, id);
splay(rot->s[1]);
break;
}
}
}
}
int find_kth(const int k)
{
int tmp = k;
node *rot = head;
while(1)
{
if (!rot)
return -1;
if ((!rot->s[0] && tmp == 1) || (rot->s[0] && tmp == rot->s[0]->size + 1))
return rot->id;
if (rot->s[0] && tmp <= rot->s[0]->size)
rot = rot->s[0];
else
{
if (rot->s[0])
tmp -= rot->s[0]->size;
tmp--;
rot = rot->s[1];
}
}
}
friend void merge(Splay &a, Splay &b);
friend void del(node *rot, Splay &d);
}island[N];
inline void merge(Splay &a, Splay &b)
{
if (a.head->size > b.head->size)
swap(a, b);
del(a.head, b);
a.head = NULL;
}
void del(Splay::node *rot, Splay &d)
{
d.insert(rot->id, rot->val);
if (rot->s[0])
del(rot->s[0], d);
if (rot->s[1])
del(rot->s[1], d);
delete rot;
}
int p[N];
int find(const int x)
{
return x == p[x] ? x : p[x] = find(p[x]);
}
void work()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &rank[i]);
p[i] = i;
island[i].insert(i, rank[i]);
}
while (m--)
{
int a, b;
scanf("%d%d", &a, &b);
int x = find(a), y = find(b);
if (x == y)
continue;
p[x] = y;
merge(island[x], island[y]);
}
int q;
scanf("%d", &q);
while (q--)
{
char c;
int a, b;
do{c = getchar();} while (c != 'B' && c != 'Q');
scanf("%d%d", &a, &b);
if (c == 'B')
{
int x = find(a), y = find(b);
if (x == y)
continue;
p[x] = y;
merge(island[x], island[y]);
}
else
printf("%d\n", island[find(a)].find_kth(b));
}
}
}
int main()
{
zyt::work();
return 0;
}

【洛谷3224/BZOJ2733】[HNOI2012]永无乡 (Splay启发式合并)的更多相关文章

  1. [BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)

    Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...

  2. 【BZOJ-2733】永无乡 Splay+启发式合并

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2048  Solved: 1078[Submit][Statu ...

  3. BZOJ 2733: [HNOI2012]永无乡 [splay启发式合并]

    2733: [HNOI2012]永无乡 题意:加边,询问一个连通块中k小值 终于写了一下splay启发式合并 本题直接splay上一个节点对应图上一个点就可以了 并查集维护连通性 合并的时候,把siz ...

  4. 洛谷.3224.[HNOI2012]永无乡(Splay启发式合并)

    题目链接 查找排名为k的数用平衡树 合并时用启发式合并,把size小的树上的所有节点插入到size大的树中,每个节点最多需要O(logn)时间 并查集维护连通关系即可 O(nlogn*insert t ...

  5. BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)

    不难...treap + 启发式合并 + 并查集 搞搞就行了 --------------------------------------------------------------------- ...

  6. BZOJ2733[HNOI2012]永无乡——线段树合并+并查集+启发式合并

    题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...

  7. bzoj2733: [HNOI2012]永无乡 线段树合并

    永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛. ...

  8. 【bzoj2733】[HNOI2012]永无乡 Treap启发式合并

    题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...

  9. 【洛谷 P3224】 [HNOI2012]永无乡(Splay,启发式合并)

    题目链接 启发式合并就是暴力合并把小的合并到大的里,一个一个插进去. 并查集维护连通性,同时保证并查集的根就是所在Splay的根,这样能省去很多操作. #include <cstdio> ...

随机推荐

  1. MAC上postman离线安装时提示加载扩展程序出错怎么办?

    目前的postman插件如果想正常使用,必须安装Postman Interceptor插件,这样才能直接使用chrome浏览器的cookie等信息,否则postman是无法完成老版本的功能的.post ...

  2. python list排序(正倒)以及获取重复数据

    mylist = [2,2,2,2,5,5,7,2,2,3,3,3,3] #<class 'list'>: [2, 2, 2, 2, 5, 5, 7, 2, 2, 3, 3, 3, 3] ...

  3. Python数据分析与展示(1)-数据分析之表示(1)-NumPy库入门

    Numpy库入门 从一个数据到一组数据 维度:一组数据的组织形式 一维数据:由对等关系的有序或无序数据构成,采用线性方式组织. 可用类型:对应列表.数组和集合 不同点: 列表:数据类型可以不同 数组: ...

  4. 移动端禁止滑动的js处理方式

    下面是禁止移动端滑动事件的方式,慎用  document.querySelector('body').addEventListener('touchmove', function (ev) {     ...

  5. String类的获取功能

    /* * String类的获取功能: * int length():获取字符串的长度,其实也就是字符个数 * char charAt(int index):获取指定索引处的字符 * int index ...

  6. [BZOJ2594] [Wc2006]水管局长数据加强版(LCT + kruskal + 离线)

    传送门 WC这个题真是丧心病狂啊,就是想学习一下怎么处理边权,给我来了这么一个破题! ORZ hzwer 临摹黄学长代码233 但还是复杂的一匹 理一下思路吧 题目大意:给定一个无向图,多次删除图中的 ...

  7. noip模拟赛 都市

    分析:是一道非常有意思的题,30分的暴力的话枚举每个位置是什么数,然后排个序,用map判一下重就好了,比较麻烦. 满分做法显然不可能讨论每个位置所有的情况,肯定是有规律的,现将这n*(n-1)/2个数 ...

  8. vue用js部分控制动画实现

    上次我们提到用vue实现过渡动画,其实只讲了vue动画的一部分,用vue自带的css状态控制动画实现,不带js http://www.cnblogs.com/null11/p/7081506.html ...

  9. IBOutlet loadView UIButton的subview数量 UIWebView

    IBOutlet声明的插座变量和属性一起使用的时候,在.m文件调用的是属性. 在loadView方法中获取view属性会产生循环引用问题并导致内存溢出. Control+E到行尾,Control+A到 ...

  10. kuangbin专题最短路 D - Silver Cow Party

    #include<iostream> #include<cstring> #include<algorithm> #include<iomanip> # ...