poj 2985 并查集+线段树 线段树求第k大数 The k-th Largest Group

本文介绍了一种使用线段树进行区间更新和查询的算法实现,通过维护区间[L, R]内值的数量,实现了对数值范围内的快速操作。文章详细展示了线段树的构建、更新和查询过程,适用于解决涉及大量区间操作的问题。

最重要的思想是,线段树里存的是值为L到R的个数,即在L-R这段区间内,值为L,L+1,L+2,L+3…R的个数。

#include<cstdio>
#include<cstring>
const int maxn = 2e5+10;
#define mid (l+r)>>1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2];//记录L到R的范围内,值为L,L+1,L+2...R-1,R的个数
int a[maxn],p[maxn];
int n;
void build(int l,int r,int rt)
{
    if(l==1)
        sum[rt]=n;//若有10个点,则值为1的点有10个
    else
        sum[rt]=0;//其他值都为0
    if(l==r)
        return ;
    int m=mid;
    build(lson);
    build(rson);
}
void update(int l,int r,int rt,int val,bool flag)
{
    if(!flag)
        sum[rt]--;
    else
        sum[rt]++;
    int m=mid;
    if(l==r)
        return ;
    if(val<=m)
        update(lson,val,flag);
    else
        update(rson,val,flag);
}
int find(int x)
{
    return x==p[x] ? x : p[x]=find(p[x]);
}
void query(int l,int r,int rt,int k)
{
    if(l==r)
    {
        printf("%d\n",l);
        return ;
    }
    int m=mid;
    if(k<=sum[rt<<1|1])
        query(rson,k);//右子树有大于等于k个数,第k个数肯定在右边
    else
        query(lson,k-sum[rt<<1|1]);
}
int main()
{
    int i,m,q,x,y,k;
    scanf("%d%d",&n,&m);
    for(i=1; i<=n; i++)
    {
        a[i]=1;   //根据题意,初始化每个点的值
        p[i]=i;   //存每个点的父节点
    }
    build(1,n,1);  //建树
    for(i=1; i<=m; i++)
    {
        scanf("%d",&q);
        if(q==0)
        {
            scanf("%d%d",&x,&y);
            x=find(x);  //查找x的父节点
            y=find(y);  //查找y的父节点
            if(x==y)    //如果x和y已经属于一个组,就不用再合并
                continue;
            update(1,n,1,a[x],false);  //将记录值为a[x]有几个数的点减1
            update(1,n,1,a[y],false);   
            update(1,n,1,a[x]+a[y],true);   //将值为a[x]+a[y]的点加1
            p[y]=x;     //并查集,将x和y归为一组
            a[x]+=a[y]; //用a[x]记录这个组的值为多少
        }
        else
        {
            scanf("%d",&k);
            query(1,n,1,k);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值