bzoj2733 [ HNOI2012 ] -- 并查集+线段树合并

用并查集记录每个联通块的根节点,每个联通块建一棵线段树,合并时合并线段树就可以了。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 #define N 100010
 6 struct node{
 7     int l,r,x;
 8 }c[N*20];
 9 int i,j,k,n,m,l,r,a[N],x,y,Rt[N],Num,b[N],f[N],f1,f2;
10 char s[2];
11 inline int Find(int x){return x==f[x]?x:f[x]=Find(f[x]);}
12 inline void Update(int& Node,int l,int r,int x){
13     if(!Node)Node=++Num;
14     if(l==r){c[Node].x++;return;}
15     int Mid=l+r>>1;
16     if(Mid<x)Update(c[Node].r,Mid+1,r,x);else Update(c[Node].l,l,Mid,x);
17     c[Node].x=c[c[Node].l].x+c[c[Node].r].x;
18 }
19 inline int Merge(int x,int y){
20     if(!y)return x;
21     if(!x)return y;
22     c[x].l=Merge(c[x].l,c[y].l);
23     c[x].r=Merge(c[x].r,c[y].r);
24     c[x].x=c[c[x].l].x+c[c[x].r].x;
25     return x;
26 }
27 inline int Query(int Node,int l,int r,int R){
28     if(l>R||!Node)return 0;
29     if(r<=R)return c[Node].x;
30     int Mid=l+r>>1;
31     return Query(c[Node].l,l,Mid,R)+Query(c[Node].r,Mid+1,r,R);
32 }
33 inline int Get_Ans(int x,int k){
34     int l=1,r=n,Mid;
35     while(l<=r){
36         Mid=l+r>>1;
37         if(Query(Rt[x],1,n,Mid)>=k)r=Mid-1;else l=Mid+1;
38     }
39     if(l>n)return -1;return b[l];
40 }
41 int main()
42 {
43     scanf("%d%d",&n,&m);
44     for(i=1;i<=n;i++)scanf("%d",&a[i]),b[a[i]]=i,f[i]=i;
45     while(m--)scanf("%d%d",&x,&y),f[Find(x)]=Find(y);
46     for(i=1;i<=n;i++)Update(Rt[Find(i)],1,n,a[i]);
47     scanf("%d",&m);
48     while(m--){
49         scanf("%s%d%d",s,&x,&y);
50         if(s[0]==‘Q‘)printf("%d\n",Get_Ans(Find(x),y));else{
51             f1=Find(x);f2=Find(y);
52             if(f1!=f2){
53                 f[f1]=f2;
54                 Rt[f2]=Merge(Rt[f1],Rt[f2]);
55             }
56         }
57     }
58     return 0;
59 }

bzoj2733

时间: 2024-10-04 15:38:05

bzoj2733 [ HNOI2012 ] -- 并查集+线段树合并的相关文章

Codeforces Gym 101194G Pandaria (2016 ACM-ICPC EC-Final G题, 并查集 + 线段树合并)

题目链接  2016 ACM-ICPC EC-Final Problem G 题意  给定一个无向图.每个点有一种颜色. 现在给定$q$个询问,每次询问$x$和$w$,求所有能通过边权值不超过w的边走到$x$的点的集合中,哪一种颜色的点出现的次数最多. 次数相同时输出编号最小的那个颜色.强制在线. 求哪种颜色可以用线段树合并搞定. 关键是这个强制在线. 当每次询问的时候,我们先要求出最小生成树在哪个时刻恰好把边权值不超过$w$的边都用并查集合并了. 在做最小生成树的时候每合并两个节点,另外开一个

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

传送门 一看到第k大就肯定要想到什么权值线段树,主席树,平衡树之类的 然后就简单了 用并查集判断连通,每个节点建立一颗权值线段树,连通的时候直接合并即可 查询时再二分递归地查找 时间复杂度好像不是很稳定...但hzwer都用这种方法水过.. 正解好像是平衡树+启发式合并,以后学TT #include <cstdio> #include <iostream> #define N 100001 int n, m, q, cnt; int a[N], f[N], sum[N * 20],

UVA1455 - Kingdom(并查集 + 线段树)

UVA1455 - Kingdom(并查集 + 线段树) 题目链接 题目大意:一个平面内,给你n个整数点,两种类型的操作:road x y 把city x 和city y连接起来,line fnum (浮点数小数点一定是0.5) 查询y = fnum这条直线穿过了多少个州和city.州指的是连通的城市. 解题思路:用并查集记录城市之间是否连通,还有每一个州的y的上下界.建立坐标y的线段树,然后每次运行road操作的时候,对范围内的y坐标进行更新:更新须要分三种情况:两个州是相离,还是相交,还是包

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

Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k

bzoj 2733 永无乡 - 并查集 - 线段树

永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输

C. Destroying Array 并查集/线段树 Intel Code Challenge Elimination Round (Div. 1 + Div. 2, combined)

题目大意就是给一个初始数组,每次删除一个点,问你剩下的连续的那些点中,最大的和是多少 2种做法 第一种是离线并查集  (这里是不会用那个res[]数组,将子的权值挪给父亲那里. 第二种是线段树区间合并.(练手 ///线段树 1 #include <algorithm> 2 #include <stack> 3 #include <istream> 4 #include <stdio.h> 5 #include <map> 6 #include &

uva 1455 - Kingdom(并查集+线段树)

题目链接:uva 1455 - Kingdom 题目大意:平面上又n个城市,初始时城市之间没有任何双向道路相连,要求一次执行指令. road A B :在城市A和城市B之间连接一条双向道路 line C:询问一条y=C的水平线上穿过多少州和这些州总共有多少城市. 一个联通分量算一个州,C保证为小数部分为0.5的实数. 解题思路:线段树维护每个位置上州和城市的个数,并查集维护哪些城市属于同一个州,并且要记录这些州上下范围.每次新建一条道路,要相应根据两个州的y坐标范围对线段树进行维护. #incl

并查集 + 线段树 LA 4730 Kingdom

题目传送门 题意:训练指南P248 分析:第一个操作可以用并查集实现,保存某集合的最小高度和最大高度以及城市个数.运用线段树成端更新来统计一个区间高度的个数,此时高度需要离散化.这题两种数据结构一起使用,联系紧密. #include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; const int M = 3 * N; const int INF = 0x3f3f3f3f; struct Point { int x, y

uvalive 4730王国kingdom(并查集+线段树)

 题意:有T组测试数据,每组数据的N表示有N个城市,接下来的N行里每行给出每个城市的坐标(0<=x,y<=1000000),然后有M(1<M<200000)个操作,操作有两类,(1)"road A B",表示将城市A和城市B通过一条道路连接,如果A和B原来属于不同的城市群,经过这个操作,A和B就在一个城市群里了,保证每条道路不会和其他道路相交(除了端点A和B).(2)"line C",表示查询当穿过y=C的直线,有多少个城市群.这几个城市