题目大意

给出若干个点集,每个点带点权。你需要完成 qqq 个操作。

  1. 合并点 uuu,vvv 所在的点集。
  2. 输出点 uuu 所在的点集中点权第 kkk 大的点的编号。

数据范围 1⩽n⩽100000,1⩽q⩽3000001\leqslant n\leqslant100000,1\leqslant q\leqslant 3000001⩽n⩽100000,1⩽q⩽300000

题解

求第k大,考虑权值线段树/Splay。
考虑到需要合并,可以考虑启发式合并。
可以发现,每个点最多被合并 log⁡n\log nlogn 次,每次插入到另一颗权值线段树/Splay的时间为 Θ(log⁡n)\Theta(\log n)Θ(logn)。故总时间复杂度是有保证的,为 Θ(n log2n)\Theta(n\,\text{log}^2n)Θ(nlog2n)。

代码

SplaySplaySplay,Time:977msTime:977msTime:977ms
这种方法没什么需要注意的,直接打就好。

#include<bits/stdc++.h>
using namespace std;
struct node{//节点int size,data,n,id;node *fa,*ch[2];inline node(int ids,int d=0,node *f=NULL):data(d),size(1),n(1),fa(f),id(ids){ch[0]=ch[1]=NULL;}inline void up(){size=n;if(ch[0]) size+=ch[0]->size;if(ch[1]) size+=ch[1]->size;}
};
#define which(p) (p->fa->ch[1]==p)
struct Splay{//Splay主体node *root;inline Splay():root(NULL){}inline void newnode(node *&p,int id,int data,node *fa){p=new node(id,data,fa);*p=node(id,data,fa);}inline node *&down(node *&p,int x){if(x==p->data) return p;return p->ch[x>p->data];}inline void rotate(node *p){int t=which(p);node *f=p->fa;if((f->ch[t]=p->ch[t^1]))p->ch[t^1]->fa=f;if((p->fa=f->fa))p->fa->ch[which(f)]=p;f->fa=p;p->ch[t^1]=f;f->up();p->up();if(p->fa==NULL)root=p;}inline void splay(node *p,node *Fa){for(;p->fa!=Fa;rotate(p))if(p->fa->fa!=Fa)rotate(which(p)==which(p->fa)?p->fa:p);}inline void insert(node *p,int id,int val){if(root==NULL){newnode(root,id,val,NULL);return ;} node *fa=p->fa;while(p!=NULL){node *t=down(p,val);if(t==p)break;fa=p;p=t;} if(p==NULL){newnode(p,id,val,fa);down(fa,val)=p;}else++p->n;splay(p,NULL);} inline void insert(int id,int x){insert(root,id,x);}inline node *kth(node *p,int k){while(p){int d=p->ch[0]?p->ch[0]->size:0;if(k>=d+1&&k<=d+p->n){splay(p,NULL);return p;}if(k<d+1) p=p->ch[0];else k-=d+p->n,p=p->ch[1];}return NULL;} inline node *kth(int k){return kth(root,k);}friend void travel_insert_del(node *t,Splay *y){y->insert(t->id,t->data);if(t->ch[0]!=NULL) travel_insert_del(t->ch[0],y);if(t->ch[1]!=NULL) travel_insert_del(t->ch[1],y);delete t;//保证空间复杂度为 $\Theta(n)$}void operator+=(Splay &_x){//启发式合并Splay *x=this,*y=&_x;travel_insert_del(y->root,x);y->root=NULL;}
}splay[100010];
int fa[100010];//并查集维护根
int findfa(int x){if(fa[x]==x) return x;return fa[x]=findfa(fa[x]);
}
void link(int u,int v){int fx=findfa(u),fy=findfa(v);if(fx==fy) return;if(splay[fx].root->size<splay[fy].root->size){fa[fx]=fy;splay[fy]+=splay[fx];}else{fa[fy]=fx;splay[fx]+=splay[fy];}
}
int n,m;
char str[110];
int main(void){scanf("%d%d",&n,&m);for(int i=1,x;i<=n;i++){fa[i]=i;scanf("%d",&x);splay[i].insert(i,x);}for(int i=1,u,v;i<=m;i++){scanf("%d%d",&u,&v);link(u,v);}scanf("%d",&m);for(int i=1,u,v;i<=m;i++){scanf("%s%d%d",str,&u,&v);if(str[0]=='Q'){node *t=splay[findfa(u)].kth(v);if(t) printf("%d\n",t->id);else printf("-1\n");}else link(u,v);}return 0;
}

权值线段数,Time:1547msTime:1547msTime:1547ms
考虑到要保证时间和空间复杂度,这里最好(必须)动态开点。

#include<bits/stdc++.h>
using namespace std;
struct tree{int l,r,d,cur;tree *left,*right;tree(int tl=0,int tr=0):l(tl),r(tr),left(NULL),right(NULL),d(0),cur(-1){} void set_up(int tl,int tr){*this=tree(tl,tr);}void insert(int x,int tcur){//加入if(l==r) return (void)(d=1,cur=tcur);int mid=(l+r)>>1;if(x<=mid){if(!left) left=new tree(l,mid);left->insert(x,tcur);}else{if(!right) right=new tree(mid+1,r);right->insert(x,tcur);}d=0;if(left) d+=left->d;if(right) d+=right->d;}int kth(int k){//排名if(k>d||k<1) return -1;if(l==r) return cur;if(left&&left->d>=k) return left->kth(k);return right->kth(k-(left?left->d:0));} friend void merge(tree*,tree*);
}t[100010];
void merge(tree *a,tree *b){//合并a->d+=b->d,b->d=b->cur=0;a->cur=max(a->cur,b->cur);if(a->left&&b->left){merge(a->left,b->left);delete b->left;b->left=NULL;}else if(b->left)a->left=b->left;//直接送过去就好if(a->right&&b->right){merge(a->right,b->right);delete b->right;b->right=NULL;}else if(b->right)a->right=b->right;//直接送过去就好
}
int fa[100010];
int findfa(int x){if(fa[x]==x) return x;return fa[x]=findfa(fa[x]);
}
void link(int u,int v){//连接int fx=findfa(u),fy=findfa(v);if(fx!=fy){if(t[fx].d>t[fy].d){fa[fy]=fx;merge(t+fx,t+fy);}else{fa[fx]=fy;merge(t+fy,t+fx);}}
}
int n,m;
char str[110];
int main(){scanf("%d%d",&n,&m);for(int i=1,x;i<=n;i++){scanf("%d",&x);t[i].set_up(1,n);t[fa[i]=i].insert(x,i);}for(int i=1,u,v;i<=m;i++){scanf("%d%d",&u,&v);link(u,v);}scanf("%d",&m);for(int i=1,u,v;i<=m;i++){scanf("%s%d%d",str,&u,&v);if(str[0]=='Q'){printf("%d\n",t[findfa(u)].kth(v));}else link(u,v);}return 0;
}

Luogu P3224 [HNOI2012]永无乡相关推荐

  1. P3224 [HNOI2012]永无乡(并查集+权值线段树合并/平衡树)

    [HNOI2012]永无乡 Code1 权值线段树天然支持merge,线段树上二分求第k小 #include<bits/stdc++.h>using namespace std; usin ...

  2. BZOJ 2733 | 洛谷 P3224 [HNOI2012]永无乡

    https://www.lydsy.com/JudgeOnline/problem.php?id=2733 https://www.luogu.org/problemnew/show/P3224 C+ ...

  3. P3224 [HNOI2012]永无乡 FHQ-Treap 启发式合并

    题意: B x y B\ x\ y B x y 表示在岛 x x x 与岛 y y y 之间修建一座新桥. Q x k Q\ x\ k Q x k 表示询问当前与岛 x x x 连通的所有岛中第 k ...

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

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

  5. 数据结构之fhq-treap——Chef and Sets,[HNOI2012]永无乡,Play with Chain,[NOI2005]维修数列(结构体版代码)

    因为非常板,所以主要是代码 Tyvj 1728 普通平衡树 Chef and Sets [HNOI2012]永无乡 Play with Chain [NOI2005]维修数列 题目很水,所以可能会出现 ...

  6. BZOJ 2733: [HNOI2012]永无乡 启发式合并treap

    2733: [HNOI2012]永无乡 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  7. bzoj 2733: [HNOI2012]永无乡(线段树启发式合并)

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 3850  Solved: 2061 [Submit][Sta ...

  8. [Bzoj2733][Hnoi2012] 永无乡(BST)(Pb_ds tree)

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 4108  Solved: 2195 [Submit][Sta ...

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

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

最新文章

  1. 线程安全与可重入函数的区别及联系
  2. 委派用户管理Hyper-v
  3. [Swift]LeetCode39. 组合总和 | Combination Sum
  4. 创建oracle数据库
  5. python 的异常及其处理
  6. solr的简单使用说明
  7. 工地小哥逆袭转行程序员的真实故事
  8. MyBatis开发文档
  9. 解决Win10任务栏不显示电池电量的问题
  10. 阿里云网盘开启公测!不限速、2T永久免费空间!!
  11. 你了解Android中的Activity吗?
  12. 用html与js实现简单日历,纯JS实现简单的日历
  13. Web项目中前端页面引用外部Js和Css的路径问题
  14. 基于nexus搭建golang代码下载代理缓存私服
  15. 91 Three.js Texture纹理属性详解
  16. 北京中医药大学本科毕业论文答辩PPT模板
  17. python random库画多彩蟒蛇_python画彩色蟒蛇
  18. 西安~培养我的文艺范儿
  19. 吉首大学第九届"新星杯"大学生程序设计大赛 C.始战
  20. 12 | 关于投简历,必须要注意的一些细节

热门文章

  1. 基于android的校园新闻app,基于Android的校园新闻app开发第三稿李威案例.doc
  2. 计算机专业竞聘词150,计算机专业组长竞聘演讲稿
  3. CN_@物理层@信噪比@分贝单位@奈奎斯特定理@香农公式@常用编码方式(曼彻斯特编码/差分曼彻斯特编码)波形图
  4. Gremlins.js – 模拟用户随机操作的 JS 测试库
  5. IMS转码网关鼎信通达-武汉迈思通信MTG3000T 移动联通电信
  6. 【linux | 打包压缩命令】
  7. iOS中实现多线程的技术方案
  8. 【调剂】3.4计算机考研其余调剂信息
  9. PyG-使用networkx对Graph进行可视化
  10. uniapp组件和HTML标签重名致设置标签样式不生效