UVALive 4730 Kingdom 线段树+并查集

题目链接:点击打开链接

题意见白书P248

思路:

先把读入的y值都扩大2倍变成整数

然后离散化一下

用线段树来维护y轴 区间上每个点的 城市数量和联通块数量,

然后用并查集维护每个联通块及联通块的最大最小y值,还要加并查集的秩来记录每个联通块的点数

然后就是模拟搞。。

T^T绝杀失败题。。似乎数组开小了一点就过了,==

#include<stdio.h>
#include<math.h>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
#define rank Rank
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define Lson(x) tree[x].l
#define Rson(x) tree[x].r
#define Sum0(x) tree[x].sum[0]
#define Lazy0(x) tree[x].lazy[0]
#define Sum1(x) tree[x].sum[1]
#define Lazy1(x) tree[x].lazy[1]
inline int Mid(int x, int y){return (x+y)>>1;}
#define N 100005
struct Point{
	int x, y;
}p[100005];
struct que{
	int u, v, op;
}Q[200005];
vector<int>G;
int n, q;
char s[10];

struct node{
	int l, r, sum[2], lazy[2];
}tree[N<<4];
void push_down(int id){
	if(Lazy1(id)) {
		Sum1(L(id)) += Lazy1(id);
		Sum1(R(id)) += Lazy1(id);
		Lazy1(L(id)) += Lazy1(id);
		Lazy1(R(id)) += Lazy1(id);
		Lazy1(id) = 0;
	}
	if(Lazy0(id)) {
		Sum0(L(id)) += Lazy0(id);
		Sum0(R(id)) += Lazy0(id);
		Lazy0(L(id)) += Lazy0(id);
		Lazy0(R(id)) += Lazy0(id);
		Lazy0(id) = 0;
	}
}
void push_up(int id){Sum0(id) = Sum0(L(id)) + Sum0(R(id));Sum1(id) = Sum1(L(id)) + Sum1(R(id));}
void build(int l, int r, int id){
	Lson(id) = l; Rson(id) = r;
	Sum0(id) = Lazy0(id) = Sum1(id) = Lazy1(id) = 0;
	if(l == r) return ;
	int mid = Mid(l, r);
	build(l, mid, L(id));
	build(mid+1, r, R(id));
}
void updata(int l, int r, int val, int now, int id){
	push_down(id);
	if(l == Lson(id) && Rson(id) == r) {
		if(now==0)Sum0(id) += val, Lazy0(id) += val;
		else Sum1(id) += val, Lazy1(id) += val;
		return ;
	}
	int mid = Mid(Lson(id), Rson(id));
	if(mid < l)
		updata(l, r, val, now, R(id));
	else if(r <= mid)
		updata(l, r, val, now, L(id));
	else {
		updata(l, mid, val, now, L(id));
		updata(mid+1, r, val, now, R(id));
	}
	push_up(id);
}
int query(int pos, int now, int id){
	push_down(id);
	if(Lson(id)==Rson(id))if(now==0)return Sum0(id); else return Sum1(id);
	int mid = Mid(Lson(id), Rson(id));
	int ans;
	if(mid < pos)
		return query(pos, now, R(id));
	else return query(pos, now, L(id));
}
int f[100005], rank[100005], S[100005], X[100005]; //每个集合的上下界
int find(int x){return x==f[x]?x:f[x] = find(f[x]);}
void Union(int x, int y){
	int fx = find(x), fy = find(y);
	if(fx == fy)return;
	if(S[fx] > S[fy]) swap(fx, fy);
	if(S[fx] <= X[fy]){
		updata(S[fx], X[fy], 1, 0, 1);
		updata(S[fx], X[fy], rank[fx] + rank[fy], 1, 1);
		updata(X[fx], S[fx], rank[fy], 1, 1);
		updata(X[fy], S[fy], rank[fx], 1, 1);
	}
	else if(X[fx] >= X[fy]) {
		updata(X[fx], S[fx], -1, 0, 1);
		updata(X[fy], X[fx], rank[fx], 1, 1);
		updata(S[fx], S[fy], rank[fx], 1, 1);
	}
	else {
		updata(X[fy], S[fx], -1, 0, 1);
		updata(X[fx], X[fy], rank[fy], 1, 1);
		updata(S[fx], S[fy], rank[fx], 1, 1);
	}
	if(rank[fy]<rank[fx])swap(fx, fy);
	f[fx] = fy;
	rank[fy] += rank[fx];
	rank[fx] = 0;
	X[fy] = min(X[fy], X[fx]);
	S[fy] = max(S[fy], S[fx]);
}

void input(){
	G.clear();
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) f[i] = i, rank[i] = 1;
	for(int i = 1; i <= n; i++) scanf("%d %d",&p[i].x, &p[i].y), p[i].y <<= 1, G.push_back(p[i].y);
	scanf("%d", &q);
	for(int i = 0; i < q; i++)
	{
		scanf("%s", s);
		if(s[0]=='r')
		{
			Q[i].op = 1;
			scanf("%d %d", &Q[i].u, &Q[i].v); Q[i].u++; Q[i].v++;
		}
		else {
			Q[i].op = 2;
			scanf("%d.5",&Q[i].u);
			Q[i].u = Q[i].u * 2+1;
			G.push_back(Q[i].u);
		}
	}
	sort(G.begin(), G.end());
	G.erase(unique(G.begin(), G.end()), G.end());
	for(int i = 1; i <= n; i++)X[i] = S[i] = p[i].y = lower_bound(G.begin(), G.end(), p[i].y) - G.begin()+1;
	for(int i = 0; i < q; i++)if(Q[i].op == 2)Q[i].u = lower_bound(G.begin(), G.end(), Q[i].u) - G.begin()+1;
}
int main() {
	int T; scanf("%d",&T);
	while(T--){
		input();
		build(1, G.size(), 1);
		for(int i = 0; i < q; i++) {
			if(Q[i].op == 1)
			{
				Union(Q[i].u, Q[i].v);
			}
			else
				printf("%d %d\n", query(Q[i].u, 0, 1), query(Q[i].u, 1, 1));
		}
	}
	return 0;
}
/*
3
11
1 7
5 7
8 6
3 5
5 5
2 3
10 3
7 2
4 1
11 1
4 6
21
road 0 1
road 3 5
line 6.5
road 4 2
road 3 8
road 4 7
road 6 9
road 4 1
road 2 7
line 4.5
line 6.5
line 3.5
line 2.5
line 5.5
road 10 0
line 5.5
line 6.5
road 0 3
line 1.5
line 6.5
line 2.5

ans:
0 0
2 8
1 5
2 8
3 10
1 5
1 6
1 6
2 11
1 9
2 11

*/

UVALive 4730 Kingdom 线段树+并查集,布布扣,bubuko.com

时间: 2024-12-13 05:53:28

UVALive 4730 Kingdom 线段树+并查集的相关文章

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

UVA 1455 - Kingdom 题目链接 题意:给定一些城市坐标点,连在一起的城市称为一个州,现在用两种操作,road表示把城市a,b建一条路,line表示询问一个y轴上穿过多少个州,和这些州共包含多少个城市 思路:利用并查集维护每个州的上界和下界还有城市个数,然后每次加进一条路的时候,根据两个集合的位置可以处理出区间的州和城市数如何进行加减,然后利用线段树搞就可以了 代码: #include <cstdio> #include <cstring> #include <

UVALive 4730 线段树+并查集

点击打开链接 题意:在坐标上给n个点,r的操作是将两个点连起来,l的操作是问你y=u的这条线连接的集合块数和这些集合内的点的个数 思路:很麻烦的一道题,在网上看了题意和做法后,开始了一下午的调bug过程,做法很好懂,我开了两个线段树,一个维护点代表的直线的集合个数,另一个则是路过集合内的点的个数,然后集合的判断直接用并查集就行了,这是两个核心,然后就是自己瞎写的了,代码丑的可以而且好像除了本人别人看着可能要骂人了,有兴趣研究的可以留言我来解答,那难的部分其实就是并查集合并时该怎么将这两个要维护的

【CF687D】Dividing Kingdom II 线段树+并查集

[CF687D]Dividing Kingdom II 题意:给你一张n个点m条边的无向图,边有边权$w_i$.有q个询问,每次给出l r,问你:如果只保留编号在[l,r]中的边,你需要将所有点分成两个集合,使得这个划分的代价最小,问最小代价是什么.一个划分的代价是指,对于所有两端点在同一集合中的边,这些边的边权最大值.如果没有端点在同一集合中的边,则输出-1. $n,q\le 1000,m\le \frac {n(n-1)} 2,w_i\le 10^9$ 题解:先考虑暴力的做法,我们将所有边按

(线段树+并查集) Codeforces Round #416 (Div. 2) E Vladik and Entertaining Flags

In his spare time Vladik estimates beauty of the flags. Every flag could be represented as the matrix n?×?m which consists of positive integers. Let's define the beauty of the flag as number of components in its matrix. We call component a set of cel

【BZOJ-3673&amp;3674】可持久化并查集 可持久化线段树 + 并查集

3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status][Discuss] Description n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0<n,m<=2*10^4 Input Output Sample Input 5 6

【BZOJ 4662】 4662: Snow (线段树+并查集)

4662: Snow Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 136  Solved: 47 Description 2333年的某一天,临冬突降大雪,主干道已经被雪覆盖不能使用.城 主 囧·雪 决定要对主干道进行一次清扫. 临冬城的主干道可以看为一条数轴.囧·雪 一共找来了n个清理工,第 i个清理工的工作范围为[li,ri],也就是说这个清理工会把[li,ri]这一 段主干道清理干净(当然已经被清理过的部分就被忽略了).当然有可能主 干道

UVALive 4730 Kingdom +段树和支票托收

主题链接:点击打开链接 题意见白书P248 思路: 先把读入的y值都扩大2倍变成整数 然后离散化一下 用线段树来维护y轴 区间上每一个点的 城市数量和联通块数量. 然后用并查集维护每一个联通块及联通块的最大最小y值.还要加并查集的秩来记录每一个联通块的点数 然后就是模拟搞. . T^T绝杀失败题..似乎数组开小了一点就过了.== #include<stdio.h> #include<math.h> #include<vector> #include<string.

【Codeforces811E】Vladik and Entertaining Flags [线段树][并查集]

Vladik and Entertaining Flags Time Limit: 20 Sec  Memory Limit: 512 MB Description n * m的矩形,每个格子上有一个数字代表颜色. q次询问,询问[l, r]有几个连通块,若颜色相同并且连通则属于同一个连通块. Input 输入第一行n,m,q. 然后一个n*m的矩形. 之后q行,每行两个整数l,r. Output 输出q行,对于每个询问输出答案. Sample Input 4 5 4 1 1 1 1 1 1 2

【XSY2707】snow 线段树 并查集

题目描述 有\(n\)个人和一条长度为\(t\)的线段,每个人还有一个工作范围(是一个区间).最开始整条线段都是白的.定义每个人的工作长度是这个人的工作范围中白色部分的长度(会随着线段改变而改变).每一天开始时你要选择一个人满足这个人的工作长度最小(如果有多个就选编号最小的).把这个人的工作区间染黑.请你输出每天你选了哪个人. 保证工作范围中左端点和右端点单调递增. \(n\leq 300000\) 题解 先把线段离散化成很多个小区间,那么每个小区间只会被染黑一次(染黑之后不会变白). 因此每次