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]<<" "; 
}
posted @ 2021-11-29 20:35  fhq_treap  阅读(43)  评论(0编辑  收藏  举报