首先对于一个连通块中,询问我们可以直接用平衡树来求出排名,那么我们可以用并查集来维护各个块中的连通情况,对于合并两个平衡树,我们可以暴力的将size小的平衡树中的所有节点删掉,然后加入大的平衡树中,因为每个点只可能被删除插入logn次,所以时间复杂度为nlog^2n。

  

/**************************************************************
    Problem: 2733
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:2112 ms
    Memory:64868 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#define maxn 100010
#define maxt 4000010
 
using namespace std;
 
int n,m;
int father[maxn],a[maxn],root[maxn];
int left[maxt],right[maxt],size[maxt],key[maxt];
int tot,save;
int adr[maxn];
 
int getfather(int x)
{
    if (father[x]==x) return x;
    return father[x]=getfather(father[x]);
}
 
void swap(int &x,int &y)
{
    int z=x;
    x=y; y=z;
}
 
void left_rotate(int &t)
{
    int k=right[t];
    right[t]=left[k];
    left[k]=t;
    size[k]=size[t];
    size[t]=size[left[t]]+size[right[t]]+;
    t=k;
}
 
void right_rotate(int &t)
{
    int k=left[t];
    left[t]=right[k];
    right[k]=t;
    size[k]=size[t];
    size[t]=size[left[t]]+size[right[t]]+;
    t=k;
}
 
void maintain(int &t,bool flag)
{
    if (!flag)
    {
        if (size[left[left[t]]]>size[right[t]])
            right_rotate(t); else
        if (size[right[left[t]]]>size[right[t]])
            left_rotate(left[t]),right_rotate(t); else return;
    } else
    {
        if (size[right[right[t]]]>size[left[t]])
            left_rotate(t); else
        if (size[left[right[t]]]>size[left[t]])
            right_rotate(right[t]),left_rotate(t); else return;
    }
    maintain(left[t],); maintain(right[t],);
    maintain(t,); maintain(t,);
}
 
void t_insert(int &t,int v)
{
    if (!t)
    {
        t=++tot;
        left[t]=right[t]=;
        key[t]=v;
        size[t]=;
    } else
    {
        size[t]++;
        if (v>key[t]) t_insert(right[t],v); else t_insert(left[t],v);
        maintain(t,v>key[t]);
    }
}
 
int t_delete(int &t,int v)
{
    size[t]--;
    if ((key[t]==v)||((v>key[t])&&(!right[t]))||((v<key[t])&&(!left[t])))
    {  
        save=key[t];
        if ((!left[t])||(!right[t]))
            t=left[t]+right[t]; else key[t]=t_delete(left[t],v+);
     
    } else
        return (v>key[t])?t_delete(right[t],v):t_delete(left[t],v);
}
 
int t_rank(int &t,int k)
{
    if (size[left[t]]+==k) return key[t];
    return (k<=size[left[t]])?t_rank(left[t],k):t_rank(right[t],k-size[left[t]]-);
}
 
void combine(int x,int y)
{
    int fx,fy;
    fx=getfather(x); fy=getfather(y);
    if (size[root[fx]]<size[root[fy]]) swap(fx,fy);
    father[fy]=fx;
    if (fx!=fy)
    {
        fy=root[fy];
        while (root[fy])
        {
            t_insert(root[fx],a[fy]);
            t_delete(root[fy],a[fy]);
        }
    }
}
 
void ask(int x,int k)
{
    x=root[getfather(x)];
    if (size[x]>=k) printf("%d\n",adr[t_rank(x,k)]); else printf("-1\n");
}
 
void init()
{
    int x,y;
    scanf("%d%d",&n,&m);
    for (int i=;i<=n;i++) scanf("%d",&a[i]);
    for (int i=;i<=n;i++) adr[a[i]]=i;
    for (int i=;i<=n;i++) father[i]=i,t_insert(root[i],a[i]);
    while (m--)
    {
        scanf("%d%d",&x,&y);
        combine(x,y);
    }
}
 
void solve()
{
    int test,x,y;
    char s[];
    scanf("%d",&test);
    while (test--)
    {
        scanf("%s%d%d",&s,&x,&y);
        if (s[]=='B')
            combine(x,y); else ask(x,y);
    }
}
 
int main()
{
    init();
    solve();
    return ;
}

bzoj 2733 平衡树启发式合并的更多相关文章

  1. bzoj 2733 Splay 启发式合并,名次树

    题意:给定一个带点权的无向图,有两种操作: 1.将两个连通分量合并. 2.查询某个连通分量里的第K大点. 题解: 用并查集维护连通关系,一开始建立n棵splay树,然后不断合并,查询. 处理技巧: 1 ...

  2. BZOJ 2809: [Apio2012]dispatching( 平衡树 + 启发式合并 )

    枚举树上的每个结点做管理者, 贪心地取其子树中薪水较低的, 算出这个结点为管理者的满意度, 更新答案. 用平衡树+启发式合并, 时间复杂度为O(N log²N) ------------------- ...

  3. ☆ [HNOI2012] 永无乡 「平衡树启发式合并」

    题目类型:平衡树启发式合并 传送门:>Here< 题意:节点可以连边(不能断边),询问任意两个节点的连通性与一个连通块中排名第\(k\)的节点 解题思路 如果不需要询问排名,那么并查集即可 ...

  4. bzoj 2809 左偏树\平衡树启发式合并

    首先我们对于一颗树,要选取最多的节点使得代价和不超过m,那么我们可以对于每一个节点维护一个平衡树,平衡树维护代价以及代价的和,那么我们可以在logn的时间内求出这个子树最多选取的节点数,然后对于一个节 ...

  5. BZOJ 2733 & splay的合并

    题意: 带权联通块,添边与查询联通块中第k大. SOL: splay合并+并查集. 我以为splay可以用奇技淫巧来简单合并...调了一下午终于幡然醒悟...于是就只好一个一个慢慢插...什么启发式合 ...

  6. 【pb_ds】【平衡树启发式合并】【并查集】bzoj2733 [HNOI2012]永无乡

    用并查集维护联通性.对每个联通块维护一个平衡树.合并时启发式合并.比较懒,用了pb_ds. #include<cstdio> #include<ext/pb_ds/assoc_con ...

  7. 【BZOJ1483】[HNOI2009]梦幻布丁(平衡树启发式合并+并查集)

    题目: BZOJ1483 分析: (这题码了一下午,码了近250行,但是意外跑的比本校各位神仙稍快,特写博客纪念) 首先能看出一个显然的结论:颜色段数只会变少不会变多. 我们考虑用并查集维护区间,对于 ...

  8. bzoj 1483 链表 + 启发式合并

    思路:将颜色相同的建成一个链表, 变颜色的时候进行链表的启发式合并.. 因为需要将小的接到大的上边,所以要用个f数组. #include<bits/stdc++.h> #define LL ...

  9. bzoj 1483 链表启发式合并

    首先我们可以比较容易的在n的时间内算出来开始的答案,我们维护一些链表,分别表示不同的颜色,那么我们在计算答案的时候,只需要扫一遍所有的链表,判断链表相邻两项是否在序列中相邻,不相邻的话肯定在这其中的一 ...

随机推荐

  1. 可用于jquery animate()方法的css属性

    * backgroundPosition * borderWidth * borderBottomWidth * borderLeftWidth * borderRightWidth * border ...

  2. [Redis]在Windows下的下载及安装

    1.下载 下载地址: https://github.com/MSOpenTech/redis, 下载并解压到特定的目录. 2.启动Redis服务端 CMD -> redis-server.exe ...

  3. 【BZOJ4892】DNA(后缀数组)

    [BZOJ4892]DNA(后缀数组) 题面 BZOJ 洛谷 题解 看到这道题目,我第一反应是\(FFT\)??? 然后大力码出了一个\(FFT\) 就像这样 #include<iostream ...

  4. BZOJ3521 [Poi2014]Salad Bar 【线段树 + 单调栈】

    题目链接 BZOJ3521 题解 容易想到用前缀和搞 如果我们令\(p\)为\(1\),\(j\)为\(-1\),记前缀和为\(s[i]\) 我们就是要找到一段区间\([l,r]\),使得 \[\fo ...

  5. BZOJ1269 [AHOI2006]文本编辑器editor 【82行splay】

    1269: [AHOI2006]文本编辑器editor Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4633  Solved: 1782 [Sub ...

  6. AOJ.综合训练.2016-11-24

    AOJ.综合训练 友情提示:不要复制粘贴,看完解析先自己尝试写一下.不行再看题解.这样才会有提高! A题 金字塔 题意分析 分别读入10个数,按照他给出的格式输出就行了.注意每有7个字符(包括空格). ...

  7. Mysql Fabric实现学习笔记

    Mysql Fabric用来管理mysql服务,提供扩展性和容易使用的系统,管理mysql分片和高可用部署(当前实现了两个特性:高可用和使用数据分片的横向扩展,能单独使用或结合使用这两个特性.). 架 ...

  8. [PKUWC2018]随机算法

    题意:https://loj.ac/problem/2540 给定一个图(n<=20),定义一个求最大独立集的随机化算法 产生一个排列,依次加入,能加入就加入 求得到最大独立集的概率 loj25 ...

  9. JavaScript URL汉字编码转换

    在使用url进行参数传递时,经常会传递一些中文名的参数或URL地址,在后台处理时会发生转换错误.在有些传递页面使用GB2312,而在接收页面使用UTF8,这样接收到的参数就可能会与原来发生不一致.使用 ...

  10. 从MYSQL数据库查出指定格式的日期

    1.用SQL语言控制: 格式如下: select DATE_FORMAT(t.startTime,"%Y-%m-%d %H:%i") AS startTime, DATE_FORM ...