题意:

平面上有\(n\)个点,有一种操作和一种查询:

  • \(road \, A \, B\):在\(a\),\(b\)两点之间加一条边
  • \(line C\):询问直线\(y=C\)经过的连通分量的个数以及这些连通分量点的总数

分析:

其实横坐标是没用的,首先可以先将纵坐标离散化。

用并查集维护点的连通性,连通分量的大小以及连通分量中纵坐标的最大值和最小值。

线段树中维护的是每条直线穿过的连通分量的个数以及点的个数之和。

当两个连通分量合并时,先把两个小连通分量从线段树中删去,然后再把合并之后的大连通分量加进去。

修改是区间修改,查询是单点查询。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn = 100000 + 10;
const int maxnode = maxn * 4; int n;
int a[maxn], tot, b[maxn]; int pa[maxn], sz[maxn], miny[maxn], maxy[maxn];
int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); } int states[maxnode], cities[maxnode]; char cmd[15]; void pushdown(int o, int* add) {
if(add[o] != 0) {
add[o<<1] += add[o];
add[o<<1|1] += add[o];
add[o] = 0;
}
} void pushdown(int o) {
pushdown(o, states);
pushdown(o, cities);
} void update(int o, int L, int R, int qL, int qR, int v1, int v2) {
if(qL <= L && R <= qR) {
states[o] += v1;
cities[o] += v2;
return;
}
pushdown(o);
int M = (L + R) / 2;
if(qL <= M) update(o<<1, L, M, qL, qR, v1, v2);
if(qR > M) update(o<<1|1, M+1, R, qL, qR, v1, v2);
} void query(int o, int L, int R, int pos) {
if(L == R) {
printf("%d %d\n", states[o], cities[o]);
return;
}
pushdown(o);
int M = (L + R) / 2;
if(pos <= M) query(o<<1, L, M, pos);
else query(o<<1|1, M+1, R, pos);
} int main()
{
int T; scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
pa[i] = i; sz[i] = 1;
int x; scanf("%d%d", &x, a + i);
b[i - 1] = a[i];
}
sort(b, b + n);
tot = unique(b, b + n) - b;
for(int i = 1; i <= n; i++) {
a[i] = lower_bound(b, b + tot, a[i]) - b;
miny[i] = maxy[i] = a[i];
} memset(states, 0, sizeof(states));
memset(cities, 0, sizeof(cities));
int m; scanf("%d", &m);
while(m--) {
scanf("%s", cmd);
if(cmd[0] == 'r') {
int a, b; scanf("%d%d", &a, &b);
a++; b++;
int fa = findset(a), fb = findset(b);
if(fa == fb) continue;
int L = miny[fa], R = maxy[fa];
if(L < R) update(1, 1, n, L + 1, R, -1, -sz[fa]);
L = miny[fb], R = maxy[fb];
if(L < R) update(1, 1, n, L + 1, R, -1, -sz[fb]);
//Union
pa[fb] = fa;
sz[fa] += sz[fb];
miny[fa] = min(miny[fa], miny[fb]);
maxy[fa] = max(maxy[fa], maxy[fb]);
L = miny[fa], R = maxy[fa];
if(L < R) update(1, 1, n, L + 1, R, 1, sz[fa]);
} else {
double ty; scanf("%lf", &ty);
int y = (int)ty + 1;
y = lower_bound(b, b + tot, y) - b;
query(1, 1, n, y);
}
}
} return 0;
}

UVa 1455 Kingdom 线段树 并查集的更多相关文章

  1. [WC2005]双面棋盘(线段树+并查集)

    线段树+并查集维护连通性. 好像 \(700ms\) 的时限把我的常数超级大的做法卡掉了, 必须要开 \(O_2\) 才行. 对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并. \(Co ...

  2. 2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集)

    2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集) https://www.luogu.com.cn/problem/CF811E Ste ...

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

    [CF687D]Dividing Kingdom II 题意:给你一张n个点m条边的无向图,边有边权$w_i$.有q个询问,每次给出l r,问你:如果只保留编号在[l,r]中的边,你需要将所有点分成两 ...

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

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status ...

  5. 【XSY2707】snow 线段树 并查集

    题目描述 有\(n\)个人和一条长度为\(t\)的线段,每个人还有一个工作范围(是一个区间).最开始整条线段都是白的.定义每个人的工作长度是这个人的工作范围中白色部分的长度(会随着线段改变而改变).每 ...

  6. bzoj 2054: 疯狂的馒头(线段树||并查集)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2054 线段树写法: 点的颜色只取决于最后一次染的颜色,所以我们可以倒着维护,如果当前区间之前 ...

  7. 【BZOJ1453】[Wc]Dface双面棋盘 线段树+并查集

    [BZOJ1453][Wc]Dface双面棋盘 Description Input Output Sample Input Sample Output HINT 题解:话说看到题的第一反应其实是LCT ...

  8. codeforces 811E Vladik and Entertaining Flags(线段树+并查集)

    codeforces 811E Vladik and Entertaining Flags 题面 \(n*m(1<=n<=10, 1<=m<=1e5)\)的棋盘,每个格子有一个 ...

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

    Vladik and Entertaining Flags Time Limit: 20 Sec  Memory Limit: 512 MB Description n * m的矩形,每个格子上有一个 ...

随机推荐

  1. 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "XXXView" nib but the view outlet was not set.' 崩溃问题

    先说下我遇到这个崩溃问题的原因: 自定义的Viewxib和系统的 View重名,导致崩溃 我的理解是我这里加载YJLoginViewController 的时候,YJLoginViewControll ...

  2. hibernate课程 初探单表映射3-5 hibernate增删改查

    本节简介: 1 增删改查写法 2 查询load和查询get方法的区别 3 demo 1 增删改查写法 增加 session.save() 修改 session.update() 删除 session. ...

  3. 零基础逆向工程26_C++_03_Vector

    1 Vector 核心代码 #define SUCCESS 1 // 成功 #define ERROR -1 // 失败 #define MALLOC_ERROR -2 // 申请内存失败 #defi ...

  4. Masonry 等间隔或等宽高排列多个控件

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...

  5. 美国绿卡基础知识:I-539和I-129表格的应用回复新帖

    美国绿卡基础知识:I-539和I-129表格的应用 发布于: 2011/07/25  8:43 am 引用     I-539,就是和万金油类似的表格.不管你是要延期,还是转换身份:不管你是 B-2 ...

  6. LeetCode Remove Nth Node From End of List 删除链表的倒数第n个结点

    /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode ...

  7. [Asp.Net] MVC 和Web API Action 获取参数的区别

    Asp.net MVC 和web api 的action 在获取从前台传入的数据是有很大不同 前台使用ajax的方式向后台发起post的请求 Content-Type:application/json ...

  8. 让SAP云平台上的Web应用使用destination服务

    首先在SAP云平台里创建一个destination,维护service的end point: 然后打开SAP云平台的WebIDE,创建一个新的文件夹和新的HTML5 Application Descr ...

  9. 【洛谷1337】[JSOI2004] 吊打XXX(模拟退火经典题)

    点此看题面 大致题意: 一个平面上有\(n\)个点,每个点有1个权值,现在要选择平面上的一个点,使这\(n\)个点的权值乘上到达选定点的距离之和最小. 模拟退火 我们可以用模拟退火来做这道题. 先将\ ...

  10. 谭浩强 c++程序设计第一章课后习题 第7题

    #include <iostream> using namespace std; int main() { int a,b,c; int f(int x,int y,int z);//这是 ...