Loading

CF702F T-Shirts

题意

\(n\) 种物品,每个物品有价格 \(c_i\),品质 \(q_i\)。对于一个来购买的人,有 \(v\) 元,他可以购买多次,每次选择买得起的所有物品中选取品质最高的买,若有多个品质相同的会买最便宜的。求能购买多少次。总共会有 \(m\) 个人。

Solution

首先考虑如果只有一个人,你显然可以把物品按照价格排序。这样的话,每一次相当于在一个前缀中选取最优的那个,可以预处理出每一个前缀会选取哪一个物品来买。然后我们端详这个被我们选中的最优物品,假如买下这个物品后拥有的钱的数量仍大于买下这个物品所需要的钱,那我们下一次必然还是买它。所以每次我们会对这个物品的价格取模。对于取模来说,拥有的钱每次至少减半,所以最多迭代 \(\log v\) 次。那对每个人暴力做就是对的了。

坏消息,读错题了,每个人每种物品只能买一件

我超我 pe 防了。所以肯定是所有人一起维护。不行我 pe 防了,看了题解。

势能分析复杂度题,看起来还是挺套路的。

肯定不能单独对每个人做,所以考虑用平衡树维护所有人。然后对物品以 \(q\) 为第一关键字,\(c\) 为第二关键字排序。顺次取物品,在平衡树上大于等于 \(c\) 的位置减去 \(c\),然后在这些位置计数器加一。

但是你考虑这样会出现一些问题,就是说可能有一些位置减去 \(c\) 之后小于前面的,使得平衡树结构被破坏,迫使我们重构平衡树。这怎么办?我们考虑一波软柿子先捏,就是对于当前的 \(c\),区间 \([0,c)\) 是不会变的,而区间 \([2c,+\infty)\) 减去 \(c\) 之后与前面的相对位置不会改变。所以真正麻烦的只有区间 \([c,2c)\) 内的人。

接下来我们考虑这些人每次减去 \(c\) 之后钱至少减半,所以每个人最多在这个区间中出现 \(\log c\) 次。所以每次将这些点暴力取出,减掉之后暴力插入,复杂度不会太高,是 \(O(n\log n\log c)\),4s 随便跑。

Code

// Problem: CF702F T-Shirts
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF702F
// Memory Limit: 2800 MB
// Time Limit: 1000000 ms

#include<bits/stdc++.h>
// #define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pb emplace_back
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define all(a) a.begin(),a.end()
#define siz(a) (int)a.size()
#define clr(a) memset(a,0,sizeof(a))
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pt(a) cerr<<#a<<'='<<a<<' '
#define pts(a) cerr<<#a<<'='<<a<<'\n'
#define int long long
using namespace std;
const int MAXN=2e5+10;
struct Tree{int ch[2],fa,v,tag,id,anstag;}tr[MAXN];
int root,tot,mem[MAXN],top,ans[MAXN];
#define ls tr[x].ch[0]
#define rs tr[x].ch[1]
int chk(int x){return tr[tr[x].fa].ch[1]==x;}
void add(int x,int m,int ct){
	if(!x) return;
	tr[x].v+=m;tr[x].tag+=m;
	ans[tr[x].id]+=ct;tr[x].anstag+=ct;
}
void pushdown(int x){
	if(ls) add(ls,tr[x].tag,tr[x].anstag);
	if(rs) add(rs,tr[x].tag,tr[x].anstag);
	tr[x].tag=tr[x].anstag=0;
}
void rot(int x){
	int f=tr[x].fa,g=tr[f].fa,k=chk(x),u=tr[x].ch[k^1];
	tr[g].ch[chk(f)]=x,tr[x].fa=g;tr[f].fa=x,tr[x].ch[k^1]=f;
	tr[f].ch[k]=u;tr[u].fa=f;
}
void splay(int x,int gl){
    while(tr[x].fa!=gl){
        int p=tr[x].fa,g=tr[p].fa;
        if(g==gl) rot(x);
        else if(chk(x)==chk(p)) rot(p),rot(x);
        else rot(x),rot(x);
    }if(!gl) root=x;
}
void ins(int val,int id){
	int x=root,f=0;
	while(x){
		pushdown(x);
		if(val<=tr[x].v) f=x,x=ls;
		else f=x,x=rs;
	}
	if(top) x=mem[top],top--;
	else x=++tot;
	ls=rs=0;
	tr[x].v=val;tr[x].id=id;
	tr[x].tag=0;tr[x].anstag=0;
	if(f)tr[x].fa=f,tr[f].ch[val>tr[f].v]=x;
	splay(x,0);
}
int pre(int val){
	int x=root,ret=0;
	while(x){
		pushdown(x);
		if(tr[x].v<val) ret=x,x=rs;
		else x=ls;
	}return ret;
}
int suf(int val){
	int x=root,ret=0;
	while(x){
		pushdown(x);
		if(tr[x].v>val) ret=x,x=ls;
		else x=rs;
	}return ret;
}
void mus(int x,int m){
	if(!x) return;
	pushdown(x);
	mus(ls,m); mus(rs,m);
	mem[++top]=x;ans[tr[x].id]++;
	ins(tr[x].v-m,tr[x].id);
}
void del(int l,int r){
	int L=pre(l),R=suf(r);
	splay(L,0);splay(R,L);
	int x=tr[R].ch[0];
	tr[R].ch[0]=tr[x].fa=0;
	add(R,-l,1);mus(x,l);
}
struct Tshirts{
	int c,q;
	void input(){cin>>c>>q;}
	bool friend operator<(Tshirts a,Tshirts b){
		if(a.q==b.q) return a.c<b.c;
		return a.q>b.q;
	}
}t[MAXN];
int fn[MAXN];
void rever(int x){
	pushdown(x);
	if(ls) rever(ls);
	if(rs) rever(rs);
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int n,m,v;cin>>n;
	rep(i,1,n) t[i].input();
	cin>>m;
	ins(-INF,0);ins(INF,0);
	rep(i,1,m) cin>>v,ins(v,i);
	sort(t+1,t+1+n);
	rep(i,1,n) del(t[i].c,t[i].c*2-1);
	rever(root);
	rep(i,1,m) cout<<ans[i]<<' ';
	return 0;
}
posted @ 2022-08-09 11:13  ZCETHAN  阅读(31)  评论(0编辑  收藏  举报