do_while_true

一言(ヒトコト)

「题解」Codeforces 1098D Eels

暴力是,每次挑出最小的两个合并。

需要观察到没有产生贡献的次数很小。考虑最小的那个数的大小,如果一次合并没有产生贡献,那么最小的数至少 \(\times 2\).所以最多会有 \(\mathcal{O}(\log (qx))=\mathcal{O}(\log q+\log x)\) 次。

根据这个来观察还有什么性质,考虑如果一次合并没有产生贡献,那么那个时刻的最小值一定是所有数从小到大排序后的一段前缀合并出来的,并且发生合并的只有这个前缀。所以将所有鱼的重量 \(a\) 从小到大排序后,一个位置的前缀和 \(s_i\times 2 <a_{i+1}\) 时不会产生贡献。

最后是套路,每 \(2^i\) 分个块(\([2^0,2^1),[2^1,2^2),[2^2,2^3),\cdots\))。这样的从小到大排序后,“ \(s_i\times 2<a_{i+1}\) ” 也就是不合法的情况出现的位置一定是块与块之间。所以每个块开一个可删堆 / multiset 即可解决。时间复杂度是 \(\mathcal{O}(q\log x)\) 的。

#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<random>
#include<set>
#include<assert.h>
#define pb emplace_back
#define mp make_pair
#define fi first
#define se second
#define dbg(x) cerr<<"In Line "<< __LINE__<<" the "<<#x<<" = "<<x<<'\n'
#define dpi(x,y) cerr<<"In Line "<<__LINE__<<" the "<<#x<<" = "<<x<<" ; "<<"the "<<#y<<" = "<<y<<'\n'
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
typedef pair<ll,int>pli;
typedef pair<ll,ll>pll;
typedef pair<int,ll>pil;
typedef vector<int>vi;
typedef vector<ll>vll;
typedef vector<pii>vpii;
typedef vector<pil>vpil;
template<typename T>T cmax(T &x, T y){return x=x>y?x:y;}
template<typename T>T cmin(T &x, T y){return x=x<y?x:y;}
template<typename T>
T &read(T &r){
	r=0;bool w=0;char ch=getchar();
	while(ch<'0'||ch>'9')w=ch=='-'?1:0,ch=getchar();
	while(ch>='0'&&ch<='9')r=r*10+(ch^48),ch=getchar();
	return r=w?-r:r;
}
template<typename T1,typename... T2>
void read(T1 &x,T2& ...y){read(x);read(y...);}
const int N=500010;
int n,cnt;
multiset<int>s[31];
ll sum[31];
signed main(){
	read(n);
	for(int i=1;i<=n;i++){
		char ch=getchar();while(ch!='-'&&ch!='+')ch=getchar();
		int x,k;read(x);
		k=31-__builtin_clz(x);
		if(ch=='+')sum[k]+=x,s[k].insert(x),++cnt;
		else sum[k]-=x,s[k].erase(s[k].lower_bound(x)),--cnt;
		ll all=0;
		int ans=-1;
		for(int o=0;o<=30;o++){
			if(s[o].empty())continue;
			if(all && all*2<(*s[o].begin()))--ans;
			all+=sum[o];
		}
		cout << max(0,cnt+ans) << '\n';
	}
	return 0;
}
posted @ 2022-11-11 09:31  do_while_true  阅读(16)  评论(0编辑  收藏  举报