Description
给出
n
件
Data Constraint
1
≤
最暴力的做法
将所有的
T
-
可持久化Treap
最近学了可持久化
Treap
,便找了道题来练练手。
上述做法是
O
(
将所有的人按照
bi
排序,建出一棵
Treap
。
然后按顺序枚举每一件
T
-
如果我们这是便简单地将两棵
因而,在合并之前,我们还需调整
T1
和
T2
,不停调整直到使得
T1
中的最大值小于等于
T2
中的最小值,随后才能合并。
对于每次调整,找出
T2
内的最小值(记为
k
),与
这样做看上去好像会超时,但我们分析一下复杂度,便能发现这是
O
(
证明:
设
于是便有
ci
>
p
>
这也就意味着每一次
v
减完
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#pragma GCC optimize(3)
#include<algorithm>
#include<ctime>
#define fo(i,j,l) for(int i=j;i<=l;i++)
#define fd(i,j,l) for(int i=j;i>=l;i--)
#define fi first
#define se second
#define random(x) rand()%x
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const ll N=42e4,maxn=6e9;
struct note{
int l,r,size;
ll rnd;
}s[N];
struct nnn{
ll v,c;
}gift[N],pe[N];
ll down[N],mo[N],va[N],h[N],dy[N];
int n,m,j,k,l,i,o,root;
ll ans[N];
void getdown(int o)
{
mo[s[o].l]-=down[o];
down[s[o].l]+=down[o];
mo[s[o].r]-=down[o];
down[s[o].r]+=down[o];
va[s[o].l]+=h[o];
va[s[o].r]+=h[o];
h[s[o].l]+=h[o];
h[s[o].r]+=h[o];
down[o]=h[o]=0;
}
int merge(int a,int b)
{
if(!(a*b))return a^b;
if(!down[a])getdown(a);
if(!down[b])getdown(b);
if(s[a].rnd<s[b].rnd){
int ls=merge(s[a].r,b);
s[a].r=ls;
s[a].size=s[s[a].l].size+s[ls].size+1;
return a;
}else{
int ls=merge(a,s[b].l);
s[b].l=ls;
s[b].size=s[ls].size+s[s[b].r].size+1;
return b;
}
}
P split(int o,int wz)
{
if(!wz)return P(0,o);
if(down[o]!=0)getdown(o);
if(s[s[o].l].size>=wz){
P ls=split(s[o].l,wz);
s[o].l=ls.se;
s[o].size=s[s[o].r].size+s[ls.se].size+1;
return P(ls.fi,o);
}else{
P ls=split(s[o].r,wz-s[s[o].l].size-1);
s[o].r=ls.fi;
s[o].size=s[s[o].l].size+s[ls.fi].size+1;
return P(o,ls.se);
}
}
int search(int o,ll p)
{
if(o==0)return 0;
if(down[o]!=0)getdown(o);
if(mo[o]>=p) return search(s[o].l,p);
else return s[s[o].l].size+1+search(s[o].r,p);
}
ll read()
{
ll o=0; char ch=' ';
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+ch-48;
return o;
}
void pri(ll o)
{
if(!o)return;
pri(o/10); putchar('0'+o%10);
}
void write(ll o)
{
if(o==0)putchar('0');
pri(o);
}
bool kmp(nnn a,nnn b){
return a.v!=b.v ? a.v>b.v : a.c<b.c;
}
bool kmp2(nnn a,nnn b){
return a.v<b.v;
}
int main()
{
cin>>n;
fo(i,1,n)gift[i].c=read(),gift[i].v=read();
sort(gift+1,gift+n+1,kmp);
cin>>m;
fo(i,1,m)pe[i].v=read(),pe[i].c=i;
sort(pe+1,pe+m+1,kmp2);
fo(i,1,m)mo[i]=pe[i].v;
srand(time(0));
fo(i,1,m){
s[i].size=1;
s[i].rnd=random(maxn);
if(i==1)root=1;else root=merge(root,i);
}
ll zd=0;
fo(i,1,n){
int k=search(root,gift[i].c);
if(k==m)continue;
if(k==0){
mo[root]-=gift[i].c;
va[root]+=1;
down[root]+=gift[i].c;
h[root]+=1;
continue;
}
P bl=split(root,k);
int le=bl.fi,ri=bl.se;
mo[ri]-=gift[i].c;
va[ri]+=1;
down[ri]+=gift[i].c;
h[ri]+=1;
if(k!=1){
P rr=split(le,k-1);
zd=mo[rr.se];
le=merge(rr.fi,rr.se);
}else zd=mo[le];
while(s[ri].size>0){
P oo=split(ri,1);
int zb=oo.fi,yb=oo.se;
if(mo[zb]>=zd){
ri=merge(zb,yb);
break;
}
int y=search(le,mo[zb]);
P kk=split(le,y);
if(y!=0)zb=merge(kk.fi,zb);
if(kk.se!=0)zb=merge(zb,kk.se);
le=zb; s[0].size=0; ri=oo.se;
}
root=merge(le,ri);
}
int y;P kk;
fo(i,1,m){
if(i!=m)kk=split(root,1),y=kk.fi;
else y=root;
ans[pe[y].c]=va[y];
root=kk.se;
}
fo(i,1,m)write(ans[i]),putchar(' ');
}