poj 2985 分类: poj 2015-0...

本文介绍了一种解决特定类型问题的方法,使用并查集和树状数组结合二分答案技巧,避免了平衡树带来的常数卡顿问题。通过实际代码展示了算法的具体实现过程。

今天xjz大爷说写写平衡树,结果此题卡平衡树常数,
听说sbt都要卡常数才能过,想想都觉得不可思议,给跪了

正解是并查集+树状数组+二分答案。
都不难写,但我觉得这题卡平衡树还挺是挺坑的。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iostream>

const int MAXN = 200005;

int fa[MAXN] = {0} ,cnt[MAXN] = {0} ,tot;
int ta[MAXN] = {0};

int n , m;

inline int lowbit(const int &x)
{
    return x&(-x);
}

inline void swap(int &a,int &b)
{
    int tmp; tmp = a, a = b ,b = tmp;
}
inline void add(int x , const int &val)
{
    while(x <= n)
    {
        ta[x] += val;
        x += lowbit(x);
    }
}
inline int count(int x)
{
    int ret = 0;

    while(x > 0)
    {
        ret += ta[x];
        x -= lowbit(x);
    }

    return ret;
}
inline int find_fa(const int x)
{
    if(fa[x] == x) return x;
    else
    {
        fa[x] = find_fa(fa[x]);  return fa[x];
    }
}

inline void gather(const int &a,const int &b)
{
    int u = find_fa(a) , v =find_fa(b);

    if(u == v)return;

    if(v < u)swap(u ,v);//make sure u<v

    add(cnt[v] , -1); add(cnt[u], -1); add(cnt[u] + cnt[v], +1); 

    cnt[u] += cnt[v] , cnt[v] = 0;

    fa[v] = u; tot --;
}

inline int find(const int &x)
{
    int l = 1, r = n;

    if(x <= count(1))return 1;

    while(l + 1 != r)
    {
        int mid = (l + r)>>1;

        if(x <= count(mid)) r = mid;
        else                l = mid;
    }
    return r;
}


int main()
{
#ifndef ONLINE_JUDGE    
    freopen("poj2985.in","r",stdin);
    freopen("poj2985.out","w",stdout);
#endif  

    scanf("%d%d",&n,&m);tot = n;

    for(int i = 1;i <= n;i++){fa[i] = i;cnt[i] = 1;}

    add(1 , n);

    for(int i = 1;i <= m;i++)
    {
        int a , b ,c;

        scanf("%d",&c);

        if(c == 0)
        {
          scanf("%d%d",&a,&b);gather(a,b);
        }
        else
        {
          scanf("%d",&a);   printf("%d\n",find(tot + 1 - a));;  
        }
    }


#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
#endif  
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://www.cnblogs.com/dashgua/p/4723098.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值