欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > Codeforces Round 966 (Div. 3) H(线段树上二分)

Codeforces Round 966 (Div. 3) H(线段树上二分)

2024/10/24 16:27:08 来源:https://blog.csdn.net/weixin_61825750/article/details/141177699  浏览:    关键词:Codeforces Round 966 (Div. 3) H(线段树上二分)

题意

在这里插入图片描述

思路

1、定义 F ( x ) F(x) F(x)代表了正整数 x x x所代表的集合负载,例如对于集合 3 , 4 , 6 , 11 {3,4,6,11} 3,4,6,11而言, F ( 5 ) = 1 , F ( 7 ) = 4 F(5) = 1 , F(7) = 4 F(5)=1F(7)=4.
2、可以发现:对于集合中相邻两个数之间的数字,其 F ( x ) F(x) F(x)是递减的,例如上述例子中 F ( 7 ) = 4 , F ( 8 ) = 3 , F ( 9 ) = 2 , F ( 10 ) = 1 F(7) = 4,F(8) = 3 , F(9) = 2 , F(10) = 1 F(7)=4,F(8)=3,F(9)=2,F(10)=1
3、对于一个询问 ? ? ?而言,我们需要找到的是 x x x的最小值,满足 k ≤ F ( x ) k \leq F(x) kF(x).
4、由于观察2,对于集合中相邻两个数之间的数字而言,若最左侧的 k > F ( x ) k > F(x) k>F(x),那么这个区间内所有的数都无法满足,因此我们只需要记录所有区间的最左侧数即可。
5、为了表示集合中最小的数左侧的 F ( x ) F(x) F(x)跟最大的数右侧的 F ( x ) F(x) F(x),我们可以默认在集合中添加 0 0 0跟一个 i n f inf inf.
6、考虑添加一个数,所有的 F ( x ) F(x) F(x)会如何变化:假设集合中小于 x x x的最大元素为 l l l,大于 x x x的最小元素为 r r r.那么 F ( l + 1 ) = x − l − 1 , F ( x + 1 ) = r − x − 1 F(l+1) = x - l - 1 , F(x+1)=r - x - 1 F(l+1)=xl1,F(x+1)=rx1.其余的由于观察2,我们都不需要统计。删除一个数也是同理。
7、对于查询而言,我们想到了一个母题:一个数组中第一个大于等于 x x x的下标。我们的思路是分治,若左侧区间的最大值大于等于 x x x,那么就对左侧区间继续查询,否则就去找右侧区间。暴力的遍历整个区间求最值的时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)的,我们考虑用线段树来维护区间最值,这样时间复杂度就变成了 O ( l o g n l o g n ) O(lognlogn) O(lognlogn),可以完成本题。

代码

// Problem: H. Ksyusha and the Loaded Set
// Contest: Codeforces - Codeforces Round 966 (Div. 3)
// URL: https://codeforces.com/contest/2000/problem/H
// Memory Limit: 512 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL N = 2e06+7;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >mi;//小根堆
priority_queue<LL> ma;//大根堆
LL gcd(LL a, LL b){return b > 0 ? gcd(b , a % b) : a;
}LL lcm(LL a , LL b){return a / gcd(a , b) * b;
}
int n , m;
template<class Info>
struct SegmentTree {int n;std::vector<Info> info;SegmentTree() : n(0) {}SegmentTree(int n_, Info v_ = Info()) {init(n_, v_);}template<class T>SegmentTree(std::vector<T> init_) {init(init_);}template<class T>void init(std::vector<T> init_) {n = init_.size();info.assign(4 << std::__lg(n), Info());std::function<void(int, int, int)> build = [&](int p, int l, int r) {if (r - l == 1) {info[p] = init_[l];return;}int m = (l + r) / 2;build(2 * p, l, m);build(2 * p + 1, m, r);pull(p);};build(1, 0, n);}void pull(int p) {info[p] = info[2 * p] + info[2 * p + 1];}void modify(int p, int l, int r, int x, const Info &v) {if (r - l == 1) {info[p] = v;return;}int m = (l + r) / 2;if (x < m) {modify(2 * p, l, m, x, v);} else {modify(2 * p + 1, m, r, x, v);}pull(p);}void modify(int p, const Info &v) {modify(1, 0, n, p, v);}Info rangeQuery(int p, int l, int r, int x, int y) {if (l >= y || r <= x) {return Info();}if (l >= x && r <= y) {return info[p];}int m = (l + r) / 2;return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);}Info rangeQuery(int l, int r) {return rangeQuery(1, 0, n, l, r);}template<class F>int findFirst(int p, int l, int r, int x, int y, F pred) {if (l >= y || r <= x || !pred(info[p])) {return -1;}if (r - l == 1) {return l;}int m = (l + r) / 2;int res = findFirst(2 * p, l, m, x, y, pred);if (res == -1) {res = findFirst(2 * p + 1, m, r, x, y, pred);}return res;}template<class F>int findFirst(int l, int r, F pred) {return findFirst(1, 0, n, l, r, pred);}template<class F>int findLast(int p, int l, int r, int x, int y, F pred) {if (l >= y || r <= x || !pred(info[p])) {return -1;}if (r - l == 1) {return l;}int m = (l + r) / 2;int res = findLast(2 * p + 1, m, r, x, y, pred);if (res == -1) {res = findLast(2 * p, l, m, x, y, pred);}return res;}template<class F>int findLast(int l, int r, F pred) {return findLast(1, 0, n, l, r, pred);}
};
struct Info {int max = 0;
};
Info operator + (Info a, Info b) {return {max(a.max , b.max)};
}
vector<Info>v(N , {0});
SegmentTree<Info>seg(v);
void solve() 
{int n;cin >> n;set<int>st;st.insert(0);st.insert(N * 2);for(int i = 0 ; i < n ; i ++){int x;cin >> x;st.insert(x);}int pre = 0;for(auto it : st){if(it == 0){pre = 0;}else{seg.modify(pre + 1 , {it - pre - 1});pre = it;}}int m;cin >> m;auto del =[&] (int x){st.erase(x);auto it = st.upper_bound(x);seg.modify(x + 1 , {});int r = *it;it--;int l = *it;seg.modify(l + 1 , {r - l - 1});};auto add =[&](int x){auto it = st.upper_bound(x);int r = *it;it--;int l = *it;seg.modify(l + 1 , {x - l - 1});seg.modify(x + 1 , {r - x - 1});st.insert(x);		};for(int i = 0 ; i < m ; i++){char op;cin >> op;if(op == '-'){int x;cin >> x;del(x);}	else if(op == '+'){int x;cin >> x;add(x);}else{int k;cin >> k;int l = 0 , r = N;while(l < r){int mid = (l + r + 1) >> 1;Info tl = seg.rangeQuery(l , mid);Info tr = seg.rangeQuery(mid , r);if(tl.max >= k){r = mid - 1;}else{l = mid;}}cout << l << " ";}}cout << endl;for(auto it : st){seg.modify(it + 1 , {});}
}            
int main() 
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cout.precision(10);int t=1;cin>>t;while(t--){solve();}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com