给出若干个点集,每个点带点权。你需要完成 q q q 个操作。
数据范围 1 ⩽ n ⩽ 100000 , 1 ⩽ q ⩽ 300000 1\leqslant n\leqslant100000,1\leqslant q\leqslant 300000 1⩽n⩽100000,1⩽q⩽300000
求第k大,考虑权值线段树/Splay。
考虑到需要合并,可以考虑启发式合并。
可以发现,每个点最多被合并 log n \log n logn 次,每次插入到另一颗权值线段树/Splay的时间为 Θ ( log n ) \Theta(\log n) Θ(logn)。故总时间复杂度是有保证的,为 Θ ( n   log 2 n ) \Theta(n\,\text{log}^2n) Θ(nlog2n)。
S p l a y Splay Splay, T i m e : 977 m s Time:977ms Time:977ms
这种方法没什么需要注意的,直接打就好。
#include
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;
}
权值线段数, T i m e : 1547 m s Time:1547ms Time:1547ms
考虑到要保证时间和空间复杂度,这里最好(必须)动态开点。
#include
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;
}