zoukankan      html  css  js  c++  java
  • 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
    ",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 }
  • 相关阅读:
    【硬件】交换机与路由器概述
    【网络】IP地址,子网掩码,网段表示法,默认网关,DNS服务器详解
    【网络】网桥
    【归档】Mysql大表归档
    【锁】Innodb锁
    【磁盘】顺序IO比随机IO快
    【硬盘】RAID卡
    【基础】占用空间大小(数据页、线程)
    【SQL】ON DUPLICATE KEY UPDATE
    【基础】Hint控制语句执行
  • 原文地址:https://www.cnblogs.com/y-m-y/p/7596303.html
Copyright © 2011-2022 走看看