B20J_2733_[HNOI2012]永无乡_权值线段树合并

Posted fcwww

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了B20J_2733_[HNOI2012]永无乡_权值线段树合并相关的知识,希望对你有一定的参考价值。

B20J_2733_[HNOI2012]永无乡_权值线段树合并

Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。现在有两种操作:B x y表示在岛 x与岛y之间修建一座新桥。Q x k表示询问当前与岛 x连通的所有岛中第k重要的是哪座岛,即所有与岛 x连通的岛中重要度排名第 k小的岛是哪座,请你输出那个岛的编号。

对于100%的数据n≤100000,m≤n,q≤300000。

分析:读懂题后发现是一道线段树合并的裸题。Q操作显然是权值线段树求区间第k小元素,B操作是合并。

直接开发现开不下,需要动态开点,一开始要开nlogn个结点。

合并操作:

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

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 using namespace std;
  5 const int N=3262145;
  6 int tree[N],lson[N],rson[N],t[N],mp[N],fa[N],idx[N],cnt;
  7 int n,m,k;
  8 char s[10];
  9 int find(int x)
 10 {
 11     return fa[x]==x?x:fa[x]=find(fa[x]);    
 12 }
 13 void bt(int l,int r,int val,int &pos)
 14 {
 15     if(pos==0)pos=++cnt;
 16     if(l==r)
 17     {
 18         t[pos]=1;
 19         return ;
 20     }
 21     int mid=l+r>>1;
 22     if(val<=mid)bt(l,mid,val,lson[pos]);
 23     else bt(mid+1,r,val,rson[pos]);
 24     t[pos]=t[lson[pos]]+t[rson[pos]];
 25 }
 26 int merge(int x,int y)
 27 {
 28     if(!x)return y;
 29     if(!y)return x;
 30     lson[x]=merge(lson[x],lson[y]);
 31     rson[x]=merge(rson[x],rson[y]);
 32     t[x]=t[lson[x]]+t[rson[x]]; 
 33     return x;
 34 }
 35 int query(int l,int r,int k,int pos)
 36 {
 37     if(l==r||k==0)
 38     {
 39         return mp[l];   
 40     }
 41     int mid=l+r>>1;
 42     if(t[pos]<k)return -1;
 43     if(t[lson[pos]]>=k)
 44     {
 45         return query(l,mid,k,lson[pos]);    
 46     }
 47     else
 48     {
 49         return query(mid+1,r,k-t[lson[pos]],rson[pos]);
 50     }
 51 }
 52 int main()
 53 {
 54     scanf("%d%d",&n,&m);
 55     for(int i=1;i<=n;i++)
 56     {
 57         fa[i]=i;
 58     }
 59     for(int i=1;i<=n;i++)
 60     {
 61         scanf("%d",&idx[i]);
 62         mp[idx[i]]=i;
 63     }
 64     for(int i=1;i<=n;i++)
 65     {
 66         tree[i]=++cnt;
 67         bt(1,n,idx[i],tree[i]);
 68     }
 69     int x,y;
 70     for(int i=1;i<=m;i++)
 71     {
 72         scanf("%d%d",&x,&y);
 73         int dx=find(x),dy=find(y);
 74         if(dx!=dy)
 75         {
 76             fa[dy]=dx;
 77             tree[dx]=merge(tree[dx],tree[dy]);  
 78         }   
 79     }
 80     scanf("%d",&k);
 81     while(k--)
 82     {
 83         scanf("%s%d%d",s,&x,&y);
 84         int dx=find(x);
 85         if(s[0]==Q)
 86         {
 87             printf("%d\n",query(1,n,y,tree[dx]));
 88         }
 89         else
 90         {
 91             int dx=find(x),dy=find(y);
 92             if(dx!=dy)
 93             {
 94                 fa[dy]=dx;
 95                 tree[dx]=merge(tree[dx],tree[dy]);
 96             }
 97         }
 98     }
 99 }
100  
101 /***************************************************************
102     Problem: 2117
103     User: 20170105
104     Language: C++
105     Result: Accepted
106     Time:644 ms
107     Memory:90164 kb
108 ****************************************************************/

 

以上是关于B20J_2733_[HNOI2012]永无乡_权值线段树合并的主要内容,如果未能解决你的问题,请参考以下文章

[bzoj2733] [HNOI2012]永无乡

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

2733: [HNOI2012]永无乡

bzoj 2733: [HNOI2012]永无乡

bzoj2733[HNOI2012]永无乡 线段树合并

BZOJ2733: [HNOI2012]永无乡