题解:P10688 Buy Tickets
前置知识
- 树状数组
- 二分
思路
如果按照正常顺序从前向后模拟,问题会变得很复杂。但是反过来,我们从最后一个人开始从后向前模拟,整个问题就会变得非常简单。
为什么呢?考虑一个简单的例子:首先来了一个人,站在第 没有素质插在第 没有素质插在了第
发现了什么?最后一个插队的人是离他所排的人最近的,而第一个插队的人是离他所排的人最远的。
所以,从后往前模拟,就可以顺利解决此题。扫描每一个人,若他排在第
如何快速获取从队头到某一处之间有多少个空位?使用树状数组,维护每一个位置上有没有人(有人为
至此,问题解决。
代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[200010],v[200010];
int ans[200010];
int c[200010];
void Add(int x,int y){
for(;x<=n;x+=x&-x) c[x]+=y;
}
int Query(int x){
int ans=0;
for(;x;x-=x&-x) ans+=c[x];
return ans;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
while(cin>>n){
for(int i=1;i<=n;++i) c[i]=0;
for(int i=1;i<=n;++i) Add(i,1);
for(int i=1;i<=n;++i) cin>>a[i]>>v[i];
for(int i=n;i>=1;--i){
int l=1,r=n;
while(l<r){
int mid=(l+r)>>1;
if(Query(mid)>=a[i]+1) r=mid;
else l=mid+1;
}
ans[l]=v[i];
Add(l,-1);
}
for(int i=1;i<=n;++i) cout<<ans[i]<<" ";
cout<<"\n";
}
return 0;
}