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

题目链接

题目大意:一个平面内,给你n个整数点,两种类型的操作:road x y 把city x 和city y连接起来,line fnum (浮点数小数点一定是0.5) 查询y = fnum这条直线穿过了多少个州和city。州指的是连通的城市。

解题思路:用并查集记录城市之间是否连通,还有每一个州的y的上下界。建立坐标y的线段树,然后每次运行road操作的时候,对范围内的y坐标进行更新;更新须要分三种情况:两个州是相离,还是相交,还是包括(这里指的是y坐标的关系);而且由于这里查询是浮点数,所以更新的时候[l,r]的时候,仅仅更新[l,r),这里的r留给它以下的点,这样每次查询的时候就能够查询(int)fnum。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std; const int maxn = 1e6 + 5;
const int N = 1e5 + 5;
#define lson(x) (x<<1)
#define rson(x) ((x<<1) | 1) struct Node { int l, r, ns, nc;
void set (int l, int r, int ns, int nc) { this->l = l;
this->r = r;
this->ns = ns;
this->nc = nc;
}
}node[4 * maxn]; void pushup (int u) { node[u].set (node[lson(u)].l, node[rson(u)].r, 0, 0);
} void add_node (int u, int adds, int addc) { node[u].ns += adds;
node[u].nc += addc;
} void pushdown (int u) { if (node[u].ns || node[u].nc) {
add_node(lson(u), node[u].ns, node[u].nc);
add_node(rson(u), node[u].ns, node[u].nc);
}
} void build (int u, int l, int r) { if (l == r) {
node[u].set (l, r, 0, 0);
return;
} int m = (l + r)>>1;
build (lson(u), l, m);
build (rson(u), m + 1, r);
pushup(u);
} void update (int u, int l, int r, int addc, int adds) { if (node[u].l >= l && node[u].r <= r) {
add_node (u, adds, addc);
return;
} int m = (node[u].l + node[u].r)>>1;
pushdown(u);
if (l <= m)
update (lson(u), l, r, addc, adds);
if (r > m)
update (rson(u), l, r, addc, adds);
pushup(u);
} int query (int u, int x) { if (node[u].l == x && node[u].r == x)
return u; int m = (node[u].l + node[u].r)>>1;
int ans; pushdown(u);
if (x <= m)
ans = query (lson(u), x);
else
ans = query (rson(u), x);
pushup(u);
return ans;
} int p[N], cnt[N], L[N], R[N];
int n, m; int getParent (int x) {
return x == p[x] ? x: p[x] = getParent (p[x]);
} void change (int u, int l, int r, int addc, int adds) { if (r < l) //注意
return;
update (u, l, r, addc, adds);
} void Union(int x, int y) { x = getParent (x);
y = getParent (y); if (x == y)
return; if (L[x] >= L[y])
swap(x, y); if (R[x] <= L[y]) {//相离 change (1, L[x], R[x] - 1, cnt[y], 0);
change (1, L[y], R[y] - 1, cnt[x], 0);
change (1, R[x], L[y] - 1, cnt[x] + cnt[y], 1);
} else if (R[y] <= R[x]) {//包括 change (1, L[x], L[y] - 1, cnt[y], 0);
change (1, R[y], R[x] - 1, cnt[y], 0);
change (1, L[y], R[y] - 1, 0, -1);
} else {//相交 change (1, L[x], L[y] - 1, cnt[y], 0);
change (1, R[x], R[y] - 1, cnt[x], 0);
change (1, L[y], R[x] - 1, 0, -1);
} p[x] = y;
cnt[y] += cnt[x];
L[y] = min (L[y], L[x]);
R[y] = max (R[y], R[x]);
} void init () { int x, y;
scanf ("%d", &n); for (int i = 0; i < n; i++) {
scanf ("%d%d", &x, &y);
p[i] = i;
cnt[i] = 1;
L[i] = R[i] = y; } scanf ("%d", &m);
build (1, 0, maxn - 5);
} void solve () { char str[100];
int x, y;
double q; for (int i = 0; i < m; i++) { scanf ("%s", str); if (str[0] == 'r') {
scanf ("%d%d", &x, &y);
Union(x, y);
} else {
scanf ("%lf", &q);
x = query (1, (int)q);
printf ("%d %d\n", node[x].ns, node[x].nc);
}
}
} int main () { int T;
scanf ("%d", &T); while (T--) { init();
solve();
}
return 0;
}

UVA1455 - Kingdom(并查集 + 线段树)的更多相关文章

  1. 并查集&线段树&树状数组&排序二叉树

    超级无敌巨牛逼并查集(带权并查集)https://vjudge.net/problem/UVALive-4487 带删点的加权并查集 https://vjudge.net/problem/UVA-11 ...

  2. 【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)

    题目 CF576E 分析: 从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下. 首先做这题之前推荐一道很相似的题:[BZOJ4025]二分图(可撤销并查集+线段树 ...

  3. BZOJ 3910 并查集+线段树合并

    思路: 1. 并查集+线段树合并 记得f[LCA]==LCA的时候 f[LCA]=fa[LCA] 2.LCT(并不会写啊...) //By SiriusRen #include <cstdio& ...

  4. 并查集 + 线段树 LA 4730 Kingdom

    题目传送门 题意:训练指南P248 分析:第一个操作可以用并查集实现,保存某集合的最小高度和最大高度以及城市个数.运用线段树成端更新来统计一个区间高度的个数,此时高度需要离散化.这题两种数据结构一起使 ...

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

     题意:有T组測试数据.每组数据的N表示有N个城市,接下来的N行里每行给出每一个城市的坐标(0<=x,y<=1000000),然后有M(1<M<200000)个操作,操作有 ...

  6. YYHS-猜数字(并查集/线段树维护)

    题目描述     LYK在玩猜数字游戏.    总共有n个互不相同的正整数,LYK每次猜一段区间的最小值.形如[li,ri]这段区间的数字的最小值一定等于xi.     我们总能构造出一种方案使得LY ...

  7. luogu5012 水の数列 (并查集+线段树)

    如果我们能求出来每个区间个数的最大分值,那就可以用线段树维护这个东西 然后出答案了 然后这个的求法和(luogu4269)Snow Boots G非常类似,就是我们把数大小排个序,每次都拿<=x ...

  8. 【CF471E】MUH and Lots and Lots of Segments 扫描线+并查集+线段树+set

    [CF471E]MUH and Lots and Lots of Segments 题意:给你平面上n条水平或竖直的,端点在整点处的线段.你需要去掉一些线段的一些部分,使得剩下的图形:1.连通,2.无 ...

  9. bzoj 3237 连通图 - 并查集 - 线段树

    Input Output Sample Input 4 5 1 2 2 3 3 4 4 1 2 4 3 1 5 2 2 3 2 1 2 Sample Output Connected Disconne ...

随机推荐

  1. iPhone5C三大看点:性能不输iPhone5 或售3399元

    乐杨俊编辑修改转载: iPhone 5C的发售时间或最早在9月18日,抢在中秋节前:最迟至国庆十一假期期间. [IT商业新闻网综合讯](记者 林涛)苹果2013年秋季发布会还有几个小时即将开幕,除了i ...

  2. PHP之验证码代码

    <?php session_start(); $checkcode=""; /*for($i=0;$i<4;$i++) { $checkcode.=dechex(ran ...

  3. Windows Azure入门教学系列 (三):创建第一个Worker Role程序

    在开始本教学之前,请确保你从Windows Azure 平台下载下载并安装了最新的Windows Azure开发工具.本教学使用Visual Studio 2010作为开发工具. 步骤一:创建解决方案 ...

  4. 1.1.0-学习Opencv与MFC混合编程之---全屏截图,保存为BMP图像(并增加快捷键)

    源代码:http://download.csdn.net/detail/nuptboyzhb/3961677 Ø  添加全屏截图菜单项,菜单项的属性如下; Ø  为该菜单项建立类向导. 编辑消息处理函 ...

  5. winform基础——数据访问及几个案例

    数据访问分为三个部分:(1)创建链接(2)创建与执行命令(3)读取或准备相关数据 一,需要引用的命名空间 using data: using data.SqlClient; 二,创建与数据库的链接—— ...

  6. Linux-C语言中gettimeofday()函数的使用方法(转载)

    1.简介: 在C语言中可以使用函数gettimeofday()函数来得到时间.它的精度可以达到微妙 2.函数原型: #include<sys/time.h> int gettimeofda ...

  7. Mac 安装工具包brew

    linux有命令行工具 apt-get ,Mac 下也有类似的brew 也就是HomeBrew 网址:http://brew.sh/index_zh-cn.html 可以看到mac安装的时候只需要执行 ...

  8. 几十篇GDI以及MFC自绘的文章

    http://www.cnblogs.com/lidabo/category/434801.html

  9. libcurl编程,整整17篇

    http://www.cnblogs.com/lidabo/category/639633.html

  10. vector中的find

    vector中的find - huangyimin的专栏 - 博客频道 - CSDN.NET vector中的find 2011-01-13 09:57 11334人阅读 评论(0) 收藏 举报 ve ...