题目传送门
分析:
对于每个人直接算物品数无法优化,考虑每个物品对人的贡献
优先价值最高的物品,那么先把物品按价值从高到低排序,每件物品会让剩余钱数(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
",ans[i]);
}