1. 程式人生 > >codeforces 702F 可持久化平衡樹

codeforces 702F 可持久化平衡樹

題意:有n種T恤,每種有一個價格ci和品質qi。有m個人要買T恤,第i個人有vi塊錢,每個人每次都買一件能買得起的qi最大的T恤。一個人只能買一種T恤一件,所有人互不影響。求最後每個人買了多少件T恤。

將T恤排序。用可持久化平衡樹維護所有人。掃一遍T恤,將錢數大於當前T恤價值的人拿出來,把他們的錢數減當前價格,再塞回去。

當減完價格後這個集合的最小元素不一定大於另一個集合的最大元素。這樣就不能merge。

不過由於當前集合中減完價格後的值小於價格的人的錢數一定至少減半,所以每個人只能有log次減完價格後的值小於價格。因此可以暴力將這些人插入。複雜度log^2

#include <bits/stdc++.h>
using namespace std; #define N 210000 #define ls ch[x][0] #define rs ch[x][1] int n,m,root; pair<int,int>a[N]; int val[N],ch[N][2],bv[N],bc[N],rnd[N],cnt[N]; void pushdown(int x) { if(!x)return; if(bv[x]) { val[ls]+=bv[x];val[rs]+=bv[x]; bv[ls]+=bv[x];bv[rs]+=bv[x]; bv[x
]=0; } if(bc[x]) { cnt[ls]+=bc[x];cnt[rs]+=bc[x]; bc[ls]+=bc[x];bc[rs]+=bc[x]; bc[x]=0; } } void split(int rt,int &x,int &y,int v) { if(!rt){x=y=0;return;} pushdown(rt); if(val[rt]<v) x=rt,split(ch[rt][1],ch[x][1],y,v); else y
=rt,split(ch[rt][0],x,ch[y][0],v); } int merge(int x,int y) { if(!x||!y)return x+y; if(rnd[x]<rnd[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; } } int insert(int x,int y) { int r1=0,r2=0; split(x,r1,r2,val[y]); r1=merge(r1,y); x=merge(r1,r2); return x; } int dfs(int x,int y) { if(!x)return y; pushdown(x); y=dfs(ls,y); y=dfs(rs,y); ch[x][0]=ch[x][1]=0; return insert(y,x); } void down(int x) { if(!x)return; pushdown(x); down(ls);down(rs); } int main() { // freopen("tt.in","r",stdin); 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]); rnd[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;bv[r2]-=c; cnt[r2]++;bc[r2]++; split(r2,r3,r4,c-1); r1=dfs(r3,r1); root=merge(r1,r4); } down(root); for(int i=1;i<=m;i++) printf("%d ",cnt[i]); return 0; }