CF702F TShirts

题目传送门

分析:
对于每个人直接算物品数无法优化,考虑每个物品对人的贡献
优先价值最高的物品,那么先把物品按价值从高到低排序,每件物品会让剩余钱数\(\geq c\)的人钱数减少\(c\),答案\(+1\)
考虑用数据结构维护这个过程,用平衡树解决,权值为钱数
每次把平衡树split成大于和不大于\(c\)的两份,大于\(c\)的减去\(c\),答案标记加一,再合并回去
发现这样直接合并就不满足平衡树的定义了
出问题的区间为\([1,c]\)\([c+1,2c]\),我们看能不能暴力合并这两个区间,把后者的元素重新暴力insert进去
发现这样复杂度没有问题,对于每个单独的值\(v\),它在某一个\(c\)的询问上被合并了,说明\(c>\frac{v}{2}\),那么\(v\)每次会减去一个大于\(\frac{v}{2}\)的数
那么一个\(v\)就最多会被减\(logv\)次,直接暴力合并即可
总复杂度\(O(nlog^2n)\)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>

#define maxn 600005
#define INF 0x3f3f3f3f

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,m;
int ch[maxn][2];
int num[maxn],ans[maxn],lznum[maxn],lzans[maxn],rd[maxn];
int rt;
struct node{
	int c,q;
}a[maxn];
inline bool cmp(node x,node y)
{return x.q==y.q?x.c<y.c:x.q>y.q;}

inline void pushdown(int x)
{
	if(lznum[x])
	{
		lznum[ch[x][0]]+=lznum[x],lznum[ch[x][1]]+=lznum[x];
		num[ch[x][0]]+=lznum[x],num[ch[x][1]]+=lznum[x];
		lznum[x]=0;
	}
	if(lzans[x])
	{
		lzans[ch[x][0]]+=lzans[x],lzans[ch[x][1]]+=lzans[x];
		ans[ch[x][0]]+=lzans[x],ans[ch[x][1]]+=lzans[x];
		lzans[x]=0;
	}
}

inline void split(int rt,int k,int &x,int &y)
{
	if(!rt){x=y=0;return;}
	pushdown(rt);
	if(num[rt]<k)x=rt,split(ch[rt][1],k,ch[rt][1],y);
	else y=rt,split(ch[rt][0],k,x,ch[rt][0]);
}
inline int merge(int x,int y)
{
	if(!x||!y)return x|y;
	if(rd[x]<rd[y]){pushdown(x),ch[x][1]=merge(ch[x][1],y);return x;}
	else{pushdown(y),ch[y][0]=merge(x,ch[y][0]);return y;}
}

inline int insert(int rt,int k)
{
	int x=0,y=0;
	split(rt,num[k],x,y);
	return merge(x,merge(k,y));
}
inline int dfs(int x,int y)
{
	if(!x)return y;
	pushdown(x);
	y=dfs(ch[x][0],y);
	y=dfs(ch[x][1],y);
	ch[x][0]=ch[x][1]=0;
	return insert(y,x);
}
inline void getans(int x)
{
	if(!x)return;pushdown(x);
	getans(ch[x][0]),getans(ch[x][1]);
}
int main()
{
	srand(114514);
	n=getint();
	for(int i=1;i<=n;i++)a[i].c=getint(),a[i].q=getint();
	sort(a+1,a+n+1,cmp);
	m=getint();
	for(int i=1;i<=m;i++)num[i]=getint(),rd[i]=rand(),rt=insert(rt,i);
	for(int i=1;i<=n;i++)
	{
		int x,y,z,w;
		split(rt,a[i].c,x,y);
		num[y]-=a[i].c,lznum[y]-=a[i].c;
		ans[y]++,lzans[y]++;
		split(y,a[i].c-1,z,w);
		x=dfs(z,x);
		rt=merge(x,w);
	}
	getans(rt);
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}

原文地址:https://www.cnblogs.com/IzayoiDoyo/p/13308347.html