[可持久化平衡树][codeforces702F]T-shirts

CF 702 F

分析:
衣服排好序后把所有人插入平衡树,然后用打标记的方式维护买的操作,就是split一下之后把权值都大于当前衣服的那棵树打上购买标记,购买标记分为ans和money两个部分,merge的时候暴力把权值小的树中所有权值大于另外一棵树中某些节点的节点丢到那棵树中,一个节点最多被丢log次所以复杂度是 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

Code:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=200005;
int n,m,root;
int ls[N],rs[N],val[N],key[N],cnt[N],add[N],ans[N];
inline void pushdown(int v){
	if(add[v]) {add[ls[v]]+=add[v];add[rs[v]]+=add[v];val[ls[v]]+=add[v];val[rs[v]]+=add[v];add[v]=0;}
	if(ans[v]) {ans[ls[v]]+=ans[v];ans[rs[v]]+=ans[v];cnt[ls[v]]+=ans[v];cnt[rs[v]]+=ans[v];ans[v]=0;}
}
void split(int k,int &x,int &y,int v){
	if(!k) {x=y=0;return;}
	pushdown(k);
	if(val[k]<v) x=k,split(rs[k],rs[x],y,v);
	else y=k,split(ls[k],x,ls[y],v);
}
int merge(int x,int y){
	if(!x || !y) return x+y;
	if(key[x]<key[y]){
		pushdown(x);
		rs[x]=merge(rs[x],y);
		return x;
	}
	else{
		pushdown(y);
		ls[y]=merge(x,ls[y]);
		return y;
	}
}
int insert(int x,int y){
	int rt1=0,rt2=0;
	split(x,rt1,rt2,val[y]);
	rt1=merge(rt1,y);
	x=merge(rt1,rt2);
	return x;
}
int build(int v,int y){
	if(!v) return y;
	pushdown(v);
	y=build(ls[v],y);
	y=build(rs[v],y);
	ls[v]=rs[v]=0;
	return insert(y,v);
}
void dfs(int v){
    if(!v)return;
    pushdown(v);
    dfs(ls[v]);dfs(rs[v]);
}
pair<int,int>a[N];
int main(){   
	scanf("%d",&n);
	for(int i=1,c,q;i<=n;i++){
		scanf("%d%d",&c,&q);
		a[i]=make_pair(-q,c);
	}
	sort(a+1,a+1+n);
	scanf("%d",&m);
	for(int i=1;i<=m;i++){   
		scanf("%d",&val[i]);
		key[i]=rand();
		root=insert(root,i);
	}
	for(int i=1;i<=n;i++){
		int c=a[i].second;
		int r1=0,r2=0,r3=0,r4=0;
		split(root,r1,r2,c);
		val[r2]-=c;add[r2]-=c;
		cnt[r2]++;ans[r2]++;
		split(r2,r3,r4,c-1);
		r1=build(r3,r1);
		root=merge(r1,r4);
	}
	dfs(root);
	for(int i=1;i<=m;i++) printf("%d ",cnt[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值