UVA 1455 Kingdom (线段树 + 并查集 + 离散化)

本文介绍了一种利用线段树数据结构处理城市间连通块问题的方法。通过离散化处理大量坐标数据,并在线段树中维护连通块数量及点的数量,实现了高效查询特定水平线上与多少连通块相连的算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

给你n 个城市,初始时,没有任何双向道路相连接。

两种操作:

1. 将A点和B点连接。

2.询问一条y = C的水平线 和多少个连通块 多少个点连接。

思路:

因为询问只是涉及到y 坐标。并且数据较大。

我们直接存下所有的y 坐标 离散化一下。

然后就可以建立线段树了。

线段树维护两个值 一个时连通块个数,一个是点的个数。

操作1 ,我们维护每个连通块 y 坐标最大和最小。  然后就是区间增减问题了。(注意交集的问题。)

操作2  直接对应输出即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 100000 + 10;
int T, n, m;
double a[maxn<<2];
int cnt;
int siz[maxn]; /// 连通块大小。
int fa[maxn];
int find(int x){
    return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}

double Max[maxn], Min[maxn];


int get(double x){ /// 二分找离散化的值。

    int l = 0, r = cnt - 1, m;
    while(l <= r){
        m = l + r >> 1;
        if (a[m] == x) return m;
        else if (a[m] > x) r = m - 1;
        else l = m + 1;
    }
}


struct Point{
    double x,y;
    void read(){
        scanf("%lf %lf",&x, &y);
    }
}p[maxn];
struct QUERY{
    int op;
    int u,v;
    double x;
}q[maxn<<1];

char cmd[20];

struct node{
    int l,r;
    long long city, state;
    int addc, adds;
}nod[maxn<<4];
void pushup(int o){
    int lson = o << 1;
    int rson = o << 1 | 1;
    nod[o].city = nod[lson].city + nod[rson].city;
    nod[o].state = nod[lson].state + nod[rson].state;
}

void pushdown(int o){
    int l = nod[o].l;
    int r = nod[o].r;
    if (l == r) return;
    int m = l + r >> 1;
    if (nod[o].addc){
        int lson = o << 1;
        int rson = o << 1 | 1;
        nod[lson].addc += nod[o].addc;
        nod[rson].addc += nod[o].addc;
        nod[lson].city += (long long)nod[o].addc * (m-l+1);
        nod[rson].city += (long long)nod[o].addc * (r-m);
        nod[o].addc = 0;
    }

    if (nod[o].adds){
        int lson = o << 1;
        int rson = o << 1 | 1;
        nod[lson].adds += nod[o].adds;
        nod[rson].adds += nod[o].adds;
        nod[lson].state += (long long)nod[o].adds * (m-l+1);
        nod[rson].state += (long long)nod[o].adds * (r-m);
        nod[o].adds = 0;
    }
}





void build(int l,int r,int o){
    nod[o].l = l;
    nod[o].r = r;
    nod[o].city = nod[o].state = 0;
    nod[o].addc = nod[o].adds = 0;
    if (l == r) return;
    int m = l + r >> 1;
    build(l, m, o << 1);
    build(m+1,r,o << 1 | 1);
}


long long ans1, ans2;

void query(int L,int R,int l,int r, int o){
    if (L <= l && r <= R){
        ans1 = nod[o].state;
        ans2 = nod[o].city;
        return;
    }
    pushdown(o);
    int m = l + r >> 1;
    if (m >= L){
        query(L, R, l, m, o<<1);
    }
    if (m < R){
        query(L, R, m+1, r, o<<1|1);
    }
}


void update_city(int L,int R,int c,int l,int r, int o){ /// 更新点
    if (L <= l && r <= R){
        nod[o].addc += c;
        nod[o].city += c * (r-l+1);
        return;
    }
    pushdown(o);
    int m = l + r >> 1;
    if (m >= L){
        update_city(L, R, c, l, m, o<<1);
    }
    if (m < R){
        update_city(L, R, c, m+1, r, o<<1|1);
    }
    pushup(o);
}

void update_state(int L,int R,int c,int l,int r, int o){ /// 更新连通块
    if (L <= l && r <= R){
        nod[o].adds += c;
        nod[o].state += c * (r-l+1);
        return;
    }
    pushdown(o);
    int m = l + r >> 1;
    if (m >= L){
        update_state(L, R, c, l, m, o<<1);
    }
    if (m < R){
        update_state(L, R, c, m+1, r, o<<1|1);
    }
    pushup(o);
}


int main(){

    scanf("%d",&T);
    while(T--){
        cnt = 0;
        scanf("%d",&n);
        for (int i = 0; i < n; ++i){
            p[i].read();
            fa[i] = i;
            Max[i] = Min[i] = p[i].y;
            siz[i] = 1;
            a[cnt++] = p[i].y;
        }

        scanf("%d",&m);
        for (int i = 0; i < m; ++i){
            scanf("%s", cmd);
            if (cmd[0] == 'r'){
                scanf("%d%d",&q[i].u, &q[i].v);
                q[i].op = 0;
            }

            else {
                scanf("%lf", &q[i].x);
                q[i].op = 1;
                a[cnt++] = q[i].x;
            }

        }

        sort(a, a+cnt); /// 离散化y坐标。
        cnt = unique(a, a + cnt) - a;
        build(0, cnt-1, 1);


        for (int i = 0; i < n; ++i){
            int id = get(p[i].y);
            update_city(id, id, 1, 0, cnt-1, 1);
            update_state(id, id, 1, 0, cnt-1, 1);
        }


        for (int i = 0; i < m; ++i){

            if (q[i].op == 1){
                int id = get(q[i].x);
                query(id, id, 0, cnt-1, 1);
                printf("%lld %lld\n", ans1, ans2);
            }

            else {
                int x = q[i].u;
                int y = q[i].v;
                if (find(x) == find(y)) continue;
                int fx = find(x), fy = find(y);


                int LY = get(Min[fx]), RY = get(Max[fx]); ///单独处理
                update_city(LY, RY, siz[fy], 0, cnt-1, 1);

                LY = get(Min[fy]); RY = get(Max[fy]); ///单独处理。
                update_city(LY, RY, siz[fx], 0, cnt-1, 1);

                double miny = min(Max[fx], Max[fy]);
                double maxy = max(Min[fx], Min[fy]);

                if (Min[fx] > Max[fy] || Min[fy] > Max[fx]){ /// 没有交集的话,直接修改。
                    double low = min(Max[fx], Max[fy]);
                    double high = max(Min[fx], Min[fy]);
                    int id1 = get(low);
                    int id2 = get(high);
//                    printf("jjjjjjj %.3f %.3f\n", low, high);
                    if (id1+1<=id2-1){
                        update_state(id1+1, id2-1, 1, 0, cnt-1, 1);
                        update_city(id1+1 ,id2-1, (siz[fx] + siz[fy]), 0, cnt-1, 1);
                    }
                }
                else { /// 有交集 要减去加重的部分。
                    int id1 = get(maxy);
                    int id2 = get(miny);
//                    printf("hhh %d %d\n", id1, id2);
                    update_state(id1, id2, -1, 0, cnt-1, 1);
                    update_city(id1 ,id2, -(siz[fx] + siz[fy]), 0, cnt-1, 1);
                }

                fa[fy] = fx;
                siz[fx] += siz[fy];
                Max[fx] = max(Max[fy], Max[fx]);
                Min[fx] = min(Min[fy], Min[fx]);
            }


        }


    }


    return 0;
}
/**
My test!
3
3
2 3
3 5
4 1
5
line 3
road 0 1
line 4
road 1 2
line 3


================


3
10
1 7
5 7
8 6
3 5
5 5
2 3
10 3
7 2
4 1
11 1
11
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


1
100 100
1
line 100.5
2
10 10
20 20
2
road 0 1
line 15.5



ans:
0 0
2 8
1 5
0 0
1 2
**/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值