CF702F T-Shirts
兄,被教育了。
考虑按照值域按\(2^x\)分块。
那么我们有\(log_2 n\)块。
考虑一次操作时,我们进行的操作。
我们一定会有\(log2_n - log_2 x\)块会同时操作。
那么此时我们有\([log_2 x - 1,log_2x)\)这块。
我们一个数每次都会跌落到下一块,只会有\(log\)次的跌落,显而易见的是小的一定先跌落。
我们用\(set\)维护一个块,那么一次操作为\(O(log)\)
那么为\(O(nlog^2n)\)
#include <bits/stdc++.h>
#define ll long long
#define N 200005
int ans[N];
int n,k;
int a[N];
int UID(int a) { return a == 0 ? 0 : 32 - __builtin_clz(a); }
struct B{
std::set<std::pair<int,int> >A;
int S,C;//S = times,C = sum x
inline void del(int c,std::set<std::pair<int,int> >::iterator it);
inline void sub(int lim,int x){//对这个快操作,lim为该块下限
if(A.size()){
// std::cout<<lim<<" "<<x<<std::endl;
int begin = A.begin() -> first - C;//最小值
if(x <= begin){//整块操作
S ++ ;
C += x;
//处理跌落块操作。
begin = A.begin() -> first - C;
while(A.size() && begin < lim){
del(0,A.begin());
if(A.size())
begin = A.begin() -> first - C;
}
}else{//暴力操作
while(A.size() && x <= A.rbegin() -> first - C){
std::set<std::pair<int,int> >::iterator it = A.end();
it -- ;
ans[it -> second] ++ ;
del(x,it);
}
}
}
}
B(){S = C = 0;}
}T[50];//块维护
inline void add(int b,int i){
int I = UID(b);
ans[i] -= T[I].S;
std::pair<int,int>a;
a.first = b + T[I].C,a.second = i;
T[I].A.insert(a);
}
inline void B::del(int c,std::set<std::pair<int,int> >::iterator it){
int x = it -> first;
int i = it -> second;
// std::cout<<c<<" "<<x<<" "<<i<<std::endl;
A.erase(it);
ans[i] += S;
add(x - c - C,i);
}
struct L{
int c,q;
}e[N];
bool operator < (L a,L b){
return (a.q == b.q) ? a.c < b.c : a.q > b.q;
}
int main(){
scanf("%d",&n);
for(int i = 1;i <= n;++i)
scanf("%d%d",&e[i].c,&e[i].q);
std::sort(e + 1,e + n + 1);
scanf("%d",&k);
for(int i = 1;i <= k;++i)
scanf("%d",&a[i]),add(a[i],i);
for(int i = 1;i <= n;++i){
for(int j = 1;j <= 31;++j)
T[j].sub(1ll << (j - 1),e[i].c);
}
for(int j = 1;j <= 31;++j){
std::set<std::pair<int,int> >::iterator it = T[j].A.begin();
while(it != T[j].A.end()){
ans[it -> second] += T[j].S;
it ++ ;
}
}
for(int i = 1;i <= k;++i)
std::cout<<ans[i]<<" ";
}