HRBUST - 2371 GT’s Dream 权值线段树

在现实中认了无数师傅却毫无长进的GT在梦中成为了某武侠世界的神。在这个世界中初始有n个人,他们各成一派。作为世界神GT总共会进行m次操作,每次操作有如下两种情况

1 x y 表示x所在的帮派吞并了y所在的帮派,若xy本来就处于同一个帮派则该操作无效。

2 k 表示GT想要知道当前第k大的帮派有多少人,若当前帮派数量少于k个则输出-1

题意:校赛中文题~~

思路:并查集+区间第K大,权值线段树裸题,赛后发现了一道和这道题差不多的题,不知是巧合还是。。看了一下那道题的题解,emmm,了解了权值线段树,(赛场上还疯狂二分,真地菜),权值线段树还是比较好理解的,线段树上的一个节点的权值如果为m的话,代表当前这个节点被访问了m次,这是可以看一下左子节点和右子节点的状态,如果要找的数大于左子节点的权值就往右侧寻找,比较好理解,,然后更新一下要找的第k大的数,例如减去左子节点的权值。。(顺便了解一下主席树或者持久化这些高级数据结构的高级操作)

点击打开链接

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=3e5+5;
int fa[maxn],ran[maxn],n,m;
void init() {
    for(int i=1;i<=n;i++) {
        fa[i]=i;
        ran[i]=0;
    }
}
int fin(int x) {
    if(fa[x]==x) {
        return x;
    }
    else return fa[x]=fin(fa[x]);
}
struct node{
    int l,r;
    int cnt;
}t[maxn<<2];

void build(int tl,int tr,int root) {
    t[root].l=tl;
    t[root].r=tr;
    if(tl==1)t[root].cnt=n;
    else t[root].cnt=0;
    if(tl==tr)return;
    int mid=(tr+tl)/2;
    build(tl,mid,root*2);
    build(mid+1,tr,root*2+1);
}

void add(int x,int root,int c) {
    t[root].cnt+=c;
    if(t[root].l==t[root].r) return;
    if(x <= t[root*2].r) add(x,root*2,c);
    else add(x,root*2+1,c);
}
int query(int k,int rt=1) {
    if(t[rt].l==t[rt].r) {
        printf("%d\n",t[rt].l);
        return 0;
    }
    if(k <= t[rt*2+1].cnt) query(k,rt*2+1);
    else query(k-t[rt*2+1].cnt,rt*2);
}
int a[maxn];
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        init();
        for(int i=1;i<=n;i++)a[i]=1;
        build(1,n,1);
        int ss=n;
        for(int i=0;i<m;i++) {
            int c;
            scanf("%d",&c);
            if(c==1) {
                int s1,s2;
                scanf("%d%d",&s1,&s2);
                int x=fin(s1);
                int y=fin(s2);
                if(x==y)continue;
                add(a[x],1,-1);
                add(a[y],1,-1);
                add(a[x]+a[y],1,1);
                fa[y]=x;
                a[x]+=a[y];
                ss--;
            }
            else {
                int k;
                scanf("%d",&k);
                if(k>ss) {
                    printf("-1\n");
                    continue;
                }
                else {
                    query(k);
                }
            }
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值