T2 礼物(gift)
礼物(gift)
题面
\(n\) 个物品,每个物品有价值 \(v_i\) 和代价 \(w_i\)。现在有 \(T\) 个询问, 每个询问对应一个奇数 \(q_i\),问选 \(q_i\) 个物品使得代价和不超过 \(m\) 的情况下价值的中位数最大是多少?
\(1\le n,T\le 10^6,1\le v_i,w_i,m\le 10^6, 1\le q_i \le n\)
思路
赛时玩了会儿游戏,然后去了个灵感爆发之地——厕所,就想到了关键思路:离线,提前处理每一个询问的。以代价为第一关键字排序后,选定一个中位数,其代价和就等于它的代价加上左右两边的 k 小值和,但后面我们要反复用所以还要可持久化。
从大往小枚举每一个数,可以用二分左右两边同时最大的 k,于是一但必它后面的数有多出来的最大值,就设置其答案为当前的价值即可。
代码
#include<bits/stdc++.h>
using namespace std;
// typedef long long ll;
#define int long long
typedef long double ld;
#define freop(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define endl '\n'
#define lb(x) ((x)&-(x))
#define inf 0x7f7f7f7f7f7f7f7f
#define pii pair<int,int>
#define fir first
#define sec second
#define mkp(a,b) make_pair(a,b)
const int N=5e5+10,M=1e6;
int n,m,T,q,ans[N];pii a[N];
class Segment_Tree{
int tot=N,dx,ans;
struct node{
int ls,rs,w,v;
}tr[N<<4];
void change(int u,int v,int l=1,int r=M){
tr[u]=tr[v],++tr[u].v,tr[u].w+=dx;
// cerr << u << ' ' << tr[u].w << ' ' << tr[u].v << endl;
if(l==r) return ;
int mid=l+r>>1;
if(dx<=mid) change(tr[u].ls=++tot,tr[v].ls,l,mid);
else change(tr[u].rs=++tot,tr[v].rs,mid+1,r);
}
int query(int u,int nw,int l=1,int r=M){
if(!nw||!u) return nw;
// cerr << u << ':' << tr[u].w << ' ' << tr[u].v << endl;
if(tr[u].v<=nw){ans+=tr[u].w;return nw-tr[u].v;}
if(l==r){ans+=nw*l;return 0;}
int mid=l+r>>1,t;
t=query(tr[u].ls,nw,l,mid);
query(tr[u].rs,t,mid+1,r);
return 0;
}
public:
inline void add(int u,int v,int x){dx=x,change(u,v);}
inline int ask(int u,int x){ans=0,query(u,x);return ans;}
}pre,bac;
signed main(){
cin.tie(0)->ios::sync_with_stdio(0);
cout.tie(0);
freop("gift");
//↑以上为初始化↑
//------------------------------
cin >> n >> m >> T;
for(int i = 1;i<=n;++i){
cin >> a[i].fir >> a[i].sec;
if(a[i].sec>m) --n,--i;
}
sort(a+1,a+n+1);
// for(int i = 1;i<=n;++i) cerr << a[i].fir << ' ' << a[i].sec << endl;
for(int i = 1;i<=n;++i)
pre.add(i,i-1,a[i].sec);
for(int i = n;i;--i)
bac.add(n-i+1,n-i,a[i].sec);
for(int i = n,lst=0;i;--i){
int l=0,r=min(i-1,n-i),mid,tm=m-a[i].sec;
while(l<r){
mid=l+r+1>>1;
// cerr << mid << ':' << pre.ask(i-1,mid) << ' ' << bac.ask(n-i,mid) << endl;
if(pre.ask(i-1,mid)+bac.ask(n-i,mid)<=tm) l=mid;
else r=mid-1;
}
// cerr << i << ' ' << l << endl;
for(;lst<=l;++lst)
ans[lst]=a[i].fir;
}
while(T--) cin >> q,cout << (ans[q/2]?ans[q/2]:-1) << endl;
return 0;
}

浙公网安备 33010602011771号