树状数组求第k大(二分做法)
由于看不懂位运算版的树状数组求第k大,只能学学二分,优秀的log²复杂度,可以接受!
算法核心:由于树状数组自带求比自己小的数有几个,我们可以求第k小,
公式:第k大 可以转化成 = 求第(n(元素总个数) - k + 1)小
例如求1 2 8 10 12,第2大,我们是不是转化成求第3小。话不多说,直接上题就懂了。
1、The k-th Largest Group
传送门
Des
初始有n个猫舍,每个猫舍都有一只猫,有两种操作。
(1)合并x,y两个猫舍的猫
(2)询问数量第k大的猫舍有几只猫
Solution
我们使用树状数组维护猫舍数量出现的次数,c[i]表示数量为i的猫舍有几个。集合之间的关系使用并查集处理即可。
Code
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 3e5 + 10;
int n, m;
int a[N], p[N], c[N];
inline int lowbit(int x)
{
return x & (-x);
}
inline void change(int i, int k)
{
for( ; i <= n; i += lowbit(i)) c[i] += k;
}
int query(int i)
{
int res = 0;
for( ; i; i -= lowbit(i)) res += c[i];
return res;
}
int findd(int x)
{
while(x != p[x]) x = p[x] = p[p[x]];
return x;
}
signed main()
{
scanf("%d%d", &n, &m);
int num = n;
for(int i = 1; i <= n; ++i) p[i] = i;
for(int i = 1; i <= n; ++i) a[i] = 1;
change(1, n);
int op, x, y;
while(m-- && scanf("%d", &op))
{
if(op == 0)
{
scanf("%d%d", &x, &y);
x = findd(x);
y = findd(y);
if(x == y) continue;
change(a[x], -1);
change(a[y], -1);
p[y] = x;
a[x] += a[y];
change(a[x], 1);
num--;
}
else
{
scanf("%d", &x);
int k = num - x + 1;
int l = 1, r = n;
while(l < r)
{
int mid = l + r >> 1;
if(query(mid) >= k) r = mid;
else l = mid + 1;
}
printf("%d\n", l);
}
}
return 0;
}
2、KiKi's K-Number
Des
传送门
题目变成了求比某个数x大的第k大是谁?然后添加了两种操作
(1)插入一个数
(2)删除一个数
Solution
直接二分x以后的区间,不断缩小大于等于k的范围
Code
#include <bits/stdc++.h>
#define MX 1e5
using namespace std;
const int N = 1e5 + 10;
int q, c[N];
inline int lowbit(int x)
{
return x & (-x);
}
inline void change(int i, int k)
{
for(; i <= MX; i += lowbit(i)) c[i] += k;
}
inline int query(int i)
{
int res = 0;
for( ; i; i -= lowbit(i)) res += c[i];
return res;
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0);
while(cin >> q)
{
memset(c, 0, sizeof c);
int op, x, k;
while(q-- && cin >> op)
{
if(op == 0)
{
cin >> x;
change(x, 1);
}
else if(op == 1)
{
cin >> x;
if(query(x) - query(x - 1) == 0) cout << "No Elment!\n";
else change(x, -1);
}
else
{
cin >> x >> k;
int cmp = query(x);
if(query(MX) - cmp < k) cout << "Not Find!\n";//如果之间的数不足k个,不存在
else
{
int l = 1, r = MX;
while(l < r)
{
int mid = l + r >> 1;
if(query(mid) - cmp >= k) r = mid;//不断逼近k个
else l = mid + 1;
}
cout << l << "\n";
}
}
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】