zoukankan      html  css  js  c++  java
  • 【题解】永无乡

    (Question)

    题目大意:给(n)个点及其权值,每次并两个点,会形成一些联通块,求一个点所在联通块的权值第(k)小的点的编号。

    读起来比较绕口,但实质就那么几个:插入,合并,求第(K)小。

    我们可以想到用线段树合并。而维护连通性,可以用那个代码量小,短小精悍的数据结构:并查集。

    具体来说,当合并(x,y)的时候,找到它们的并查集的(root),以总体来合并,方便维护信息。合并完之后,将两个点的并查集(root)重置一下,记为总的那个根就行。

    对于查询,我们可以在树上二分求(k)小。无解当且仅当它所在联通块的节点数小于(k)

    注意输出是输出点的编号,维护一个映射:(f:v->Num)即可。(Num)是编号,(v)是权值。

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=500000;
    int rt[MAXN],ch[MAXN<<5][2],rub[MAXN<<5],n,m,tot,cnt;
    int v[MAXN],f[MAXN],Q;
    int val[MAXN<<5],vb[MAXN];
    char c[5];
    inline int build(){return (cnt?rub[cnt--]:++tot);}
    void del(int x){
    	ch[x][0]=ch[x][1]=val[x]=0;
    	rub[++cnt]=x;return;
    } 
    void modify(int &p,int l,int r,int pos,int vv){
    	if(!p)p=build();
    	val[p]+=vv;
    	if(l==r)return;
    	int mid=l+r>>1;
    	if(pos<=mid)modify(ch[p][0],l,mid,pos,vv);
    	else modify(ch[p][1],mid+1,r,pos,vv);
    }
    int query(int p,int l,int r,int ql,int qr){
    	if(l>qr||r<ql)return 0;
    	if(l>=ql&&r<=qr)return val[p];
    	int mid=l+r>>1;
    	return query(ch[p][0],l,mid,ql,qr)+query(ch[p][1],mid+1,r,ql,qr);
    }
    int kth(int p,int l,int r,int k){
    	if(l==r)return l;
    	int mid=l+r>>1;
    	if(val[ch[p][0]]>=k)return kth(ch[p][0],l,mid,k);
    	else return kth(ch[p][1],mid+1,r,k-val[ch[p][0]]);
    }
    int merge(int x,int y){
    	if(!x||!y)return x+y;
    	val[x]+=val[y];
    	ch[x][0]=merge(ch[x][0],ch[y][0]);
    	ch[x][1]=merge(ch[x][1],ch[y][1]);
    	del(y);return x;
    }
    inline int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i)scanf("%d",&v[i]),f[i]=i,vb[v[i]]=i;
    	for(int i=1;i<=n;++i)modify(rt[i],1,n,v[i],1);
    	for(int i=1;i<=m;++i){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		x=find(x),y=find(y);
    		if(x==y)continue; 
    		rt[x]=merge(rt[x],rt[y]);f[y]=x;
    	}
    	scanf("%d",&Q);
    	while(Q--){
    		scanf("%s",c);
    		int x,y;
    		scanf("%d%d",&x,&y);
    		if(c[0]=='B'){
    			int X=x,Y=y;
    			X=find(X),Y=find(Y);
    			if(X==Y)continue;
    			rt[X]=merge(rt[X],rt[Y]);f[Y]=X;
    		}
    		else{
    			int G=v[x];
    			x=find(x);
    			if(y>query(rt[x],1,n,1,n)){
    				cout<<-1<<endl;
    				continue;
    			}
    			printf("%d
    ",vb[kth(rt[x],1,n,y)]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    C++11 function用法 可调用对象模板类
    2017年团体程序设计天梯赛
    CCCC 以及 hihocoder offer收割赛11 ~~~
    Wannafly Union Goodbye 2016-A//初识随机化~
    Good Bye 2016 //智商再次下线,边界爆炸.....
    连做两场goodbye2016是怎样的体验.....
    2016CCPC 合肥--最大公约数//每一年通向它的路上,多少人折戟沉沙,多少人功败垂成,有人一战成名,有人从头再来。
    2016 CCPC 合肥赛区 平行四边形//打铁记录..... 背锅还是我在行 此处@ctr 233
    补题安排及挂机....
    BZOJ3670:[NOI2014]动物园
  • 原文地址:https://www.cnblogs.com/h-lka/p/12562065.html
Copyright © 2011-2022 走看看