https://codeforces.com/contest/1997/problem/E
题意:开始是1级,从下标1开始往后遍历数组a,如果a[i]>=level,就会战斗,否则跳过。当战斗满k次,就会升1级。2e5次级别询问,当k时x时,在i位置的等级是多少。
处理出x位置开始,下一个含有k个a[i]大于等于lvl的位置。
如果成功这样离线询问,对所有k=1~n枚举等级的变化,那么就是$\sum_{i=1}^{i=n} n/i \approx nlogn$级别的数据,是能做的。
至于,求下一个含有k个a[i]大于等于level的位置,这个操作做到logn以内即可,可能有线段树等做法但是没太想出来。
这里有题解的排序+set的做法:外层遍历lvl,已知升级为lvl的位置,求对每个k升级为lvl+1的位置。cur维护刚刚升级为lvl的位置。ord位置维护a[i]>=lvl的下标,alive维护这些下标的排名(因此能查询下一个有k个值大于等于lvl的位置)
如果对于某个k,在x-1位置战斗后升为lvl级,那么在即alive里面求 排名为:x的排名+k-1的那个数nxt,意味着在nxt位置战斗过后,将会升级为lvl+1。
时间复杂度$O(nlog^2n)$
这把ordered_set整出来的操作没见过啊。。。自己改了一下还TLE了,不想弄了
#include<bits/stdc++.h>
#include "ext/pb_ds/assoc_container.hpp"
#define LOCAL//delete when submit!!!!!!
using namespace __gnu_pbds;
using namespace std;
template <typename T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
int n,q;
vector<bool> ans;
set<int> alive;
vector<int> ord;
vector<vector<pii>> query;
vector<int> a;
vector<int> cur;
void solve(){
cin>>n>>q;
ans.resize(q);
ord.resize(n);
a.assign(n,0);
cur.assign(n+1,0);
query = vector<vector<pii>>(n+1);
iota(ord.begin(),ord.end(),0);
for(int i=0;i<n;i++) cin>>a[i];
sort(ord.begin(),ord.end(),[&](int x,int y){return a[x]>a[y];});
for(int j=0;j<q;j++){
int i,x; cin>>i>>x;
i--;
query[x].push_back({i,j});
}
for(int i=1;i<=n;i++){
sort(query[i].begin(),query[i].end(),[](pii x,pii y){return x.first>y.first;});
}
ordered_set<int> alive(ord.begin(),ord.end());
for(int lvl = 1;lvl<=n;lvl++){
for(int k=1;k<=n;k++){
if(cur[k]>=n) continue;
int x = alive.order_of_key(cur[k]);
int nxt = x+k-1>=int(alive.size())?n:*alive.find_by_order(x+k-1);
while(!query[k].empty() && query[k].back().first <=nxt) {
ans[query[k].back().second] = (a[query[k].back().first] >= lvl);
query[k].pop_back();
}
cur[k] = nxt+1;
}
while(!ord.empty() && a[ord.back()] == lvl){
alive.erase(ord.back());
ord.pop_back();
}
}
for(int i=0;i<q;i++){
cout<<(ans[i]?"YES":"NO")<<'\n';
}
}
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0);std::cout.tie(0);std::cin.tie(0);
int T = 1;
#ifdef MULTI_TEST
cin>>T;
#endif
while(T--){
solve();
}
return 0;
}