bzoj2733 永无乡 平衡树按秩合并

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2733

题意:动态连边,求出某个联通块中权值第$k$小的点。

首先,看到名次果断想平衡树……查询这个问题很好解决,但是合并……恐怕只能暴力修改了吧……

这时候我们需要一个武器:启发式合并,通俗的讲就是小的插到大的里面去突然污了起来。我们可以想象一下,如果把大的那棵树合并到小的那棵去,那么每个节点暴力合并……时间代价不堪设想……因此按秩合并可以有效减短合并时间……然后就是暴力插点删点就行了……

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define lc(x) ((x)->ch[0])
  6 #define rc(x) ((x)->ch[1])
  7 #define size(x) ((x)?(x->siz):0)
  8 using namespace std;
  9 const int maxn=100005;
 10 int n,m;
 11 struct node
 12 {
 13     int val,fix,siz,id;
 14     node *ch[2];
 15     node(){}
 16     node(int v=0,int d=0):val(v),fix(rand()),id(d),siz(1){memset(ch,0,sizeof(ch));}
 17     void maintain(){siz=1+size(ch[0])+size(ch[1]);}
 18 };
 19 struct Treap
 20 {
 21     node *root[maxn];
 22     void rotate(node* &rt,int d)
 23     {
 24         node *t=rt->ch[d^1];rt->ch[d^1]=t->ch[d];t->ch[d]=rt;
 25         rt->maintain();t->maintain();rt=t;
 26     }
 27     void insert(node* &rt,int x,int y)
 28     {
 29         if(!rt){rt=new node(x,y);return;}
 30         int d=rt->val>x;insert(rt->ch[d^1],x,y);rt->maintain();
 31         if(rt->ch[d^1]->fix<rt->fix)rotate(rt,d);
 32         rt->maintain();
 33     }
 34     void del(node* &rt,int x)
 35     {
 36         if(rt->val==x)
 37         {
 38             if(lc(rt)&&rc(rt))
 39             {
 40                 int d=lc(rt)->fix>rc(rt)->fix;
 41                 rotate(rt,d);del(rt->ch[d],x);
 42             }
 43             else
 44             {
 45                 node *t=NULL;
 46                 if(lc(rt))t=lc(rt);else t=rc(rt);
 47                 delete(rt);rt=t;
 48             }
 49         }
 50         else
 51         {
 52             int d=rt->val>x;
 53             del(rt->ch[d^1],x);rt->maintain();
 54             if(rt->ch[d^1]->fix>rt->fix)rotate(rt,d);
 55         }
 56     }
 57     int rank(node *rt,int x)
 58     {
 59         int res=0;
 60         while(rt)
 61             if(x>rt->val)res+=size(lc(rt))+1,rt=rc(rt);
 62             else rt=lc(rt);
 63         return res;
 64     }
 65     int kth(node *rt,int x)
 66     {
 67         while(rt)
 68         {
 69             if(size(lc(rt))+1==x)return rt->id;
 70             if(size(lc(rt))+1>x)rt=lc(rt);
 71             else x-=size(lc(rt))+1,rt=rc(rt);
 72         }
 73         return -1;
 74     }
 75     void mergeto(node* src,node* &to)
 76     {
 77         if(lc(src))mergeto(lc(src),to);
 78         if(rc(src))mergeto(rc(src),to);
 79         insert(to,src->val,src->id);
 80         delete src,src=NULL;
 81     }
 82 }T;
 83 int f[maxn];
 84 int getfa(int x)
 85 {
 86     return f[x]==x?x:f[x]=getfa(f[x]);
 87 }
 88 void unionn(int x,int y)
 89 {
 90     x=getfa(x),y=getfa(y);
 91     if(x!=y)
 92     {
 93         if(T.root[x]->siz<T.root[y]->siz)f[x]=y,T.mergeto(T.root[x],T.root[y]);
 94         else f[y]=x,T.mergeto(T.root[y],T.root[x]);
 95     }
 96 }
 97 int a[maxn];
 98 int haha()
 99 {
100     scanf("%d%d",&n,&m);
101     for(int i=1;i<=n;i++)scanf("%d",&a[i]),T.root[i]=new node(a[i],i),f[i]=i;
102     for(int i=1;i<=m;i++)
103     {
104         int x,y;scanf("%d%d",&x,&y);
105         unionn(x,y);
106     }
107     int q;scanf("%d",&q);
108     for(int i=1;i<=q;i++)
109     {
110         char opt[3];int x,y;scanf("%s%d%d",opt,&x,&y);
111         if(opt[0]==‘Q‘)printf("%d\n",T.kth(T.root[getfa(x)],y));
112         else unionn(x,y);
113     }
114 }
115 int sb=haha();
116 int main(){;}

bzoj2733

时间: 2024-11-08 15:36:10

bzoj2733 永无乡 平衡树按秩合并的相关文章

BZOJ2733 永无乡【splay启发式合并】

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含

Bzoj 2733: [HNOI2012]永无乡 数组Splay+启发式合并

2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3955  Solved: 2112[Submit][Status][Discuss] Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达

[bzoj2733]永无乡&amp;&amp;[bzoj3545]Peaks

并不敢说完全会了线段树合并,只是至少知道原理写法了...还是太菜了,每天被大佬吊锤qwq 我看到的几道线段树合并都是权值线段树的合并.这个算法适用范围应该只是01线段树的. 这两道算入门题了吧... 发现粘题面没人看(自己都懒得看),以后粘链接加题意吧. 永无乡 给$n$个没有连边的带权点,动态加边,询问$u$所在连通块权值第$k$大的点是什么.$n \leq 1e5 , q\leq 3e5$ 离线永无乡?? 给定森林,点有点权有重复!,边有边权.询问$u$所在连通块,只能走边权小于$w$的边,

BZOJ 2733 HNOI 2012 永无乡 平衡树启发式合并

题目大意:有一些岛屿,一开始由一些无向边连接.后来也有不断的无向边加入,每一个岛屿有个一独一无二的重要度,问任意时刻的与一个岛屿联通的所有岛中重要度第k大的岛的编号是什么. 思路:首先连通性一定要用并查集维护,然后就是联通快内的第k大问题,显然是平衡树.但是并查集的合并怎么搞?可以考虑按秩合并,这样的话就保证每次在平衡树中处理的元素尽量的少,就可以水过这个题了. 注意一下输出-1的判断. CODE: #include <map> #include <cstdio> #include

【BZOJ2733】永无乡(线段树合并)

题意:支持合并,求块内K小数 对于 100%的数据 n≤100000,m≤n,q≤300000 思路:对于每一个块建立一棵动态开点的线段树,暴力(启发式?)合并后二分下就行了 merge用函数的方式写因为懒得讨论x,y其中一个为0的情况,反正是把节点y并到x上 为什么这么暴力都不T?大概是因为随机数据的块的大小太平均了吧 var t:array[0..2100000,0..1]of longint; sum:array[0..2100000]of longint; fa,a,root:array

bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)

这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例,submit,1A! 哇真的舒服 调试输出懒得删了QwQ #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<queue> #include

bzoj2733 永无乡 splay树的启发式合并

https://vjudge.net/problem/HYSBZ-2733 给一些带权点,有些点是互相连通的, 然后给出2种操作,在两点间加一条边,或者询问一个点所在的连通块内的第k小值的编号 并查集辅助+splay的启发式合并就行 由于结构简单,动态开点线段树合并也可以做 我写的是splay,由于一个奇怪的bug,我一气之下把之前的核心代码里的我自己写的splay和rotate代码全换成板子了 #include <bits/stdc++.h> #define endl '\n' #defin

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

Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k

【bzoj2733】[HNOI2012]永无乡 线段树合并

Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k