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

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

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

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;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/118052.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Matlab矩阵复制扩充

    考虑这个问题:定义一个简单的行向量a    如何复制10行呢?即:    同理,对于一个列向量,如何复制10列呢?  关键函数1:repmat(A,m,n):将向量/矩阵在垂直方向复制m次,在水平方向复制n次。      再举一个例子,对于a=[12;34]:         垂直方向复制3次,水平方向复制2次,

    2022年4月8日
    61
  • python画图函数

    python画图函数python画图函数

    2022年6月3日
    37
  • uart 时序_8080接口时序

    uart 时序_8080接口时序数据传送速率用波特率来表示,指单位时间内载波参数变化的次数,或每秒钟传送的二进制位数  如每秒钟传送240个字符,而每个字符包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为2400Bd  传输时序如下图    在UART中,信号线上共有两种状态,分别用逻辑1(高电平)和逻辑0(低电平)来区分  在空闲时,数据线应该保持在逻辑高电平状态  其中…

    2025年11月16日
    3
  • java中.的意思_java中“:”的意思是什么?

    java中.的意思_java中“:”的意思是什么?展开全部代码块是一种常见的代码形式。他用62616964757a686964616fe58685e5aeb931333365653331大括号“{}”将多行代码封装在一起,形成一个独立的代码区,这就构成了代码块。代码块的格式如下:1、普通代码块:是最常见的代码块,在方法里用一对“{}”括起来的数据,就是普通的代码块,2、构造代码块:是在类中直接定义的,用“{}”括起来的代码。每次调用构造方法前执行…

    2022年7月9日
    25
  • SSM-Mybatis(4)「建议收藏」

    SSM-Mybatis(4)「建议收藏」缓存什么是缓存[Cache]存在内存中的临时数据将用户经常查询的数据放在缓存(内存)中,用户去查询数据的时候就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。为什么使用缓存减少和数据库的数据交换次数,较少系统开销,提高系统效率什么样的数据库能使用缓存经常查询并且不经常改变的数据Mybatis缓存MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。默认情况下,只启用了本地的会话缓存,它仅

    2022年8月9日
    6
  • 1.如何实现MT4帐号同步交易?

    1.如何实现MT4帐号同步交易?使用本跟单EA,可以实现在同一台计算机上运行两个(或更多个)MetaTrader4自动复制交易。您使用其中一个MT4帐号手动交易或者使用EA自动交易,那么其它一个(或更多个)MT4,会立即复制此帐号中的订单。您可以运行多个喊单EA和多个跟单EA,可以实现一个帐号跟多个帐号,或者多个帐号跟一个帐号,又或者多个帐号跟多个帐号。用来喊单的MT4帐号不需要帐号必须拥交易权限,因此,可以使用MT4“投资者”密码登录。投资者密码,又称呼“只读密码、观摩密码”。…

    2022年5月30日
    36

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号