BZOJ2733 [HNOI2012]永无乡(并查集+线段树合并)

题目大意:

在$n$个带权点上维护两个操作:

  1)在点$u,v$间连一条边;

  2)询问点$u$所在联通块中权值第$k$小的点的编号,若该联通块中的点的数目小于$k$,则输出$-1$;


 

传送门

上周的模拟赛在一道线段树合并的题目上gg了,来学习一个。

对每一个联通块,我们维护一棵权值线段树。查询时,若左子树大小大于等于$k$进入左子树,否则进入右子树;

因为每棵线段树同构,所以对于任意两棵线段树可以进行合并操作:

1 int merge(int x,int y){
2     if(!x)return y;
3     if(!y)return x;
4     t[x].lson=merge(t[x].lson,t[y].lson);
5     t[x].rson=merge(t[x].rson,t[y].rson);
6     t[x].s=t[t[x].lson].s+t[t[x].rson].s;
7     return x;
8 }

利用并查集判断两个点是否连通,若不联通,则合并两个联通块的线段树即可;

代码:

 1 #include<cstring>
 2 #include<cmath>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cctype>
 6 #define foru(i,x,y) for(int i=x;i<=y;i++)
 7 using namespace std;
 8 const int N=1e5+100;
 9 
10 struct node{int s,lson,rson;}t[N*20];
11 int n,m,a[N],f[N],fx,fy,cnt,rt[N],idx[N];
12 
13 int gf(int k){return k==f[k]?k:f[k]=gf(f[k]);}
14 
15 int read(){
16     static int f,x;static char ch;
17     x=f=0;ch=getchar();
18     while(!isdigit(ch)){f=(ch=='-');ch=getchar();}
19     while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
20     return f?-x:x;
21 }
22 
23 #define ls t[k].lson
24 #define rs t[k].rson
25 #define mid ((L+R)>>1)
26 
27 void upd(int &k,int L,int R,int p){
28     if(p<L||p>R)return;
29     if(!k)k=++cnt;
30     if(L==R){t[k].s=1;return;}
31     upd(ls,L,mid,p);upd(rs,mid+1,R,p);
32     t[k].s=t[ls].s+t[rs].s;
33 }
34 
35 int query(int k,int L,int R,int p){
36     if(L==R)return L;
37     if(t[ls].s<p)return query(rs,mid+1,R,p-t[ls].s);
38     return query(ls,L,mid,p);
39 }
40 
41 int merge(int x,int y){
42     if(!x)return y;
43     if(!y)return x;
44     t[x].lson=merge(t[x].lson,t[y].lson);
45     t[x].rson=merge(t[x].rson,t[y].rson);
46     t[x].s=t[t[x].lson].s+t[t[x].rson].s;
47     return x;
48 }
49 
50 int main(){
51     //freopen("1.in","r",stdin);
52     memset(t,0,sizeof(t));
53     n=read();m=read();
54     foru(i,1,n)a[i]=read(),f[i]=i;
55     foru(i,1,m){
56         fx=gf(read());fy=gf(read());
57         f[fx]=fy;
58     }
59     foru(i,1,n){
60         upd(rt[gf(i)],1,n,a[i]);
61         idx[a[i]]=i;
62     }
63     int q=read(),x,y;
64     char ch[10];
65     while(q--){
66         scanf("%s%d%d",ch,&x,&y);
67         fx=gf(x);fy=gf(y);
68         if(ch[0]=='Q')
69             printf("%d\n",t[rt[fx]].s>=y?idx[query(rt[fx],1,n,y)]:-1);
70         else if(fx!=fy){
71             f[fx]=fy;
72             rt[fy]=merge(rt[fx],rt[fy]);
73         }
74     }
75     return 0;
76 }

 

posted @ 2017-09-26 13:32  羊毛羊  阅读(217)  评论(0编辑  收藏  举报