Luogu P3224 [HNOI2012]永无乡
题目大意
给出若干个点集,每个点带点权。你需要完成 qqq 个操作。
- 合并点 uuu,vvv 所在的点集。
- 输出点 uuu 所在的点集中点权第 kkk 大的点的编号。
数据范围 1⩽n⩽100000,1⩽q⩽3000001\leqslant n\leqslant100000,1\leqslant q\leqslant 3000001⩽n⩽100000,1⩽q⩽300000
题解
求第k大,考虑权值线段树/Splay。
考虑到需要合并,可以考虑启发式合并。
可以发现,每个点最多被合并 logn\log nlogn 次,每次插入到另一颗权值线段树/Splay的时间为 Θ(logn)\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]永无乡相关推荐
- P3224 [HNOI2012]永无乡(并查集+权值线段树合并/平衡树)
[HNOI2012]永无乡 Code1 权值线段树天然支持merge,线段树上二分求第k小 #include<bits/stdc++.h>using namespace std; usin ...
- BZOJ 2733 | 洛谷 P3224 [HNOI2012]永无乡
https://www.lydsy.com/JudgeOnline/problem.php?id=2733 https://www.luogu.org/problemnew/show/P3224 C+ ...
- 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 ...
- BZOJ 2733: [HNOI2012]永无乡 [splay启发式合并]
2733: [HNOI2012]永无乡 题意:加边,询问一个连通块中k小值 终于写了一下splay启发式合并 本题直接splay上一个节点对应图上一个点就可以了 并查集维护连通性 合并的时候,把siz ...
- 数据结构之fhq-treap——Chef and Sets,[HNOI2012]永无乡,Play with Chain,[NOI2005]维修数列(结构体版代码)
因为非常板,所以主要是代码 Tyvj 1728 普通平衡树 Chef and Sets [HNOI2012]永无乡 Play with Chain [NOI2005]维修数列 题目很水,所以可能会出现 ...
- BZOJ 2733: [HNOI2012]永无乡 启发式合并treap
2733: [HNOI2012]永无乡 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
- bzoj 2733: [HNOI2012]永无乡(线段树启发式合并)
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 3850 Solved: 2061 [Submit][Sta ...
- [Bzoj2733][Hnoi2012] 永无乡(BST)(Pb_ds tree)
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 4108 Solved: 2195 [Submit][Sta ...
- [BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)
Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...
最新文章
- 线程安全与可重入函数的区别及联系
- 委派用户管理Hyper-v
- [Swift]LeetCode39. 组合总和 | Combination Sum
- 创建oracle数据库
- python 的异常及其处理
- solr的简单使用说明
- 工地小哥逆袭转行程序员的真实故事
- MyBatis开发文档
- 解决Win10任务栏不显示电池电量的问题
- 阿里云网盘开启公测!不限速、2T永久免费空间!!
- 你了解Android中的Activity吗?
- 用html与js实现简单日历,纯JS实现简单的日历
- Web项目中前端页面引用外部Js和Css的路径问题
- 基于nexus搭建golang代码下载代理缓存私服
- 91 Three.js Texture纹理属性详解
- 北京中医药大学本科毕业论文答辩PPT模板
- python random库画多彩蟒蛇_python画彩色蟒蛇
- 西安~培养我的文艺范儿
- 吉首大学第九届"新星杯"大学生程序设计大赛 C.始战
- 12 | 关于投简历,必须要注意的一些细节
热门文章
- 基于android的校园新闻app,基于Android的校园新闻app开发第三稿李威案例.doc
- 计算机专业竞聘词150,计算机专业组长竞聘演讲稿
- CN_@物理层@信噪比@分贝单位@奈奎斯特定理@香农公式@常用编码方式(曼彻斯特编码/差分曼彻斯特编码)波形图
- Gremlins.js – 模拟用户随机操作的 JS 测试库
- IMS转码网关鼎信通达-武汉迈思通信MTG3000T 移动联通电信
- 【linux | 打包压缩命令】
- iOS中实现多线程的技术方案
- 【调剂】3.4计算机考研其余调剂信息
- PyG-使用networkx对Graph进行可视化
- uniapp组件和HTML标签重名致设置标签样式不生效