UVALive 4730 - Kingdom(并查集+线段树)

题目链接 https://cn.vjudge.net/problem/UVALive-4730

【题意】
平面上有n个城市,初始时城市之间没有任何双向道路相连,你的任务是依次执行以下指令
road A B 在城市A,B之间建立一条双向道路,保证这条道路不和其它道路在非端点处相交
line C 询问一条y=C的水平线和多少个州相交,以及这些州一共包含多少个城市,在任意时刻,每一组连通的城市形成一个州,保证C的小数部分为0.5

【输入格式】
多组输入,第一行为数据组数T. 每组数据第一行为一个整数n(1<=n<=1e5)代表城市数量,以下n行每行两个整数x,y(0 <= x,y <= 1e6)城市编号为0~n-1. 下一行为指令总数m(1<=m<=200000)以下m行每行一条指令,其中A,B为不同的整数且0<=A< B< N, C是小数部分保证为0.5的实数,且0 < C <1000000. 不会有两条道路连接相同的城市,每组数据至少有一条line指令

【输出格式】
对于每条line指令,输出y=C穿过的州的数目以及这些州包含的城市总数

【思路】
把每个城市抽象成点,题目中的州其实就是一个连通块,我们可以用并查集来维护一个连通块的信息,我们需要维护一个连通块中城市的数目,还有就是纵坐标的最大值和最小值以便进行合并。而合并操作又可以借助于线段树来完成,首先可以将坐标统一乘以2使得坐标值均为整数,之后对y轴上的每一个点抽象成线段树的一个叶子结点,线段树叶子结点维护2个信息,即这一点的坐标穿过的州的数量和对应城市的数量(非叶结点这两个值是无意义的)合并两个连通块的过程其实是把原来的两个连通块删掉,加入合并后的新连通块。比如在合并两个连通块A和B的时候,首先把A,B原来各自的区间对应的州的数量减1,城市数量减去自己的城市数量,然后在合并后的新的区间中使得州的数量加1,城市数量加上A,B城市的总数量.可以用lazy标记维护区间和来实现区间更新,最后单点查询即可因为只有叶子结点的信息有意义.

#include<bits/stdc++.h>
#define node tree[id]
#define lson tree[id<<1]
#define rson tree[id<<1|1]
using namespace std;

const int maxn=1000005;
const int maxm=2000050;

struct Tree{
    int left,right;
    int num,city;
    int lazy1,lazy2;
};

int n,m;
int par[maxn];
int maxy[maxn],miny[maxn],cnt[maxn];
int x[maxn],y[maxn];
Tree tree[maxm<<2];

void init(){
    for(int i=0;i<=n;++i) par[i]=i;
    memset(maxy,0,sizeof(maxy));
    memset(miny,0,sizeof(miny));
    memset(cnt,0,sizeof(cnt));
}

int find(int x){ return x==par[x]?x:par[x]=find(par[x]); }

void pushup(int id){
    node.num=lson.num+rson.num;
    node.city=lson.city+rson.city;
}

void pushdown(int id){
    if(node.lazy1 && node.left!=node.right){
        lson.lazy1+=node.lazy1;
        lson.num+=(lson.right-lson.left+1)*node.lazy1;
        rson.lazy1+=node.lazy1;
        rson.num+=(rson.right-rson.left+1)*node.lazy1;
        node.lazy1=0;
    }
    if(node.lazy2 && node.left!=node.right){
        lson.lazy2+=node.lazy2;
        lson.city+=(lson.right-lson.left+1)*node.lazy2;
        rson.lazy2+=node.lazy2;
        rson.city+=(rson.right-rson.left+1)*node.lazy2;
        node.lazy2=0;
    }
}

void build(int id,int le,int ri){
    node.left=le;
    node.right=ri;
    node.num=node.city=0;
    node.lazy1=node.lazy2=0;
    if(le==ri) return;
    int mid=(le+ri)>>1;
    build(id<<1,le,mid);
    build(id<<1|1,mid+1,ri);
}

void update(int id,int le,int ri,int a,int b){
    if(node.left==le && node.right==ri){
        node.lazy1+=a;
        node.num+=(node.right-node.left+1)*a;
        node.lazy2+=b;
        node.city+=(node.right-node.left+1)*b;
        return;
    }
    pushdown(id);
    int mid=(node.left+node.right)>>1;
    if(ri<=mid) update(id<<1,le,ri,a,b);
    else if(le>mid) update(id<<1|1,le,ri,a,b);
    else{
        update(id<<1,le,mid,a,b);
        update(id<<1|1,mid+1,ri,a,b);
    }
    pushup(id);
}

int query(int id,int pos){
    if(node.left==node.right) return id;
    pushdown(id);
    int mid=(node.left+node.right)>>1;
    if(pos<=mid) return query(id<<1,pos);
    else return query(id<<1|1,pos);
}

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out2.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        init();
        int maxr=0;
        for(int i=0;i<n;++i){
            scanf("%d%d",&x[i],&y[i]);
            y[i]<<=1;
            maxr=max(maxr,y[i]);
            maxy[i]=miny[i]=y[i];
            cnt[i]=1;
        }
        build(1,0,maxr);
        for(int i=0;i<n;++i){ update(1,y[i],y[i],1,1); }
        scanf("%d",&m);
        while(m--){
            char op[10];
            scanf("%s",op);
            if(op[0]=='r'){
                int a,b;
                scanf("%d%d",&a,&b);
                a=find(a);
                b=find(b);
                if(a!=b){
                    update(1,miny[a],maxy[a],-1,-cnt[a]);
                    update(1,miny[b],maxy[b],-1,-cnt[b]);
                    par[b]=a;
                    maxy[a]=max(maxy[a],maxy[b]);
                    miny[a]=min(miny[a],miny[b]);
                    cnt[a]+=cnt[b];
                    update(1,miny[a],maxy[a],1,cnt[a]);
                }
            }
            else{
                double c;
                scanf("%lf",&c);
                int p=c*2+0.5;
                if(p>maxr) puts("0 0");
                else{
                    int id=query(1,p);
                    printf("%d %d\n",node.num,node.city);
                }
            }
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/wafish/p/10465262.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值