0
点赞
收藏
分享

微信扫一扫

POJ--2985 The k-th Largest Group(第K大组,带权并查集+树状数组+二分)

Hyggelook 2022-09-26 阅读 32

地址:​​http://poj.org/problem?id=2985​​

题意:

输入n,m。共n只猫,m组询问。

1,L,R。L号猫所在组和R号猫所在组合并

0,x。查询第x大组有几只猫。

解析:

理解了好久的说。。。最最重要的还是树状数组的本质要理解好,要不代码写再多也没用。

树状数组:c[i]表示所含人数在[i-lowbit(i)+1,i]的组有几个

hav[i]:表示i号猫所在组有几只猫

pr[i]:并查集

first:初始化:此代码是非常有利于理解这道题的。意思是:含有人数为1的组数有n组。

update(1,n);

1:当两个组L和R合并时,那么人数为hv[L]和hv[R]的组数都要-1。新组人数为:hv[L]+hv[R],+1。而且总组数--

1);
update(hv[f2],-1);
update(hv[f1]+hv[f2],1);
pr[f2]=f1;
hv[f1]+=hv[f2];
all--;

2:询问时,把第k大转化为第n-k+1小。

接下来,就是二分了。md=(L+R)>>1。

getsum(md):人数为[md-lowbit(md)+1,md]的组有几个?是不是接近n-k+1?

以此类推~直到找到答案

总的AC代码,cin会超时

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int pr[maxn],hv[maxn],c[maxn];
int n,m;
int find(int x)
{
if(x!=pr[x])
return pr[x]=find(pr[x]);
return x;
}
int lowbit(int x){
return x&(-x);
}
void update(int id,int x)
{
for(int i=id;i<=maxn;i+=lowbit(i))
c[i]+=x;
}
int getsum(int x)
{
int ans=0;
for(int i=x;i>=1;i=i-lowbit(i))
ans+=c[i];
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
pr[i]=i;
hv[i]=1;
}
update(1,n);
int all=n;
while(m--)
{
int x;
scanf("%d",&x);
if(x==0)
{
int l,r;
scanf("%d%d",&l,&r);
int f1=find(l);
int f2=find(r);
if(f1==f2)
continue;
update(hv[f1],-1);
update(hv[f2],-1);
update(hv[f1]+hv[f2],1);
pr[f2]=f1;
hv[f1]+=hv[f2];
all--;
}
else
{
int y;
scanf("%d",&y);
y=all-y+1;
int l=1,r=n;
while(l<=r)
{
int md=(l+r)>>1;
if(getsum(md)>=y)
r=md-1;
else
l=md+1;
// cout<<l<<"-"<<r<<endl;
}
cout<<l<<endl;
}
}
}

 



举报

相关推荐

0 条评论