题意:有n个人在排队,他们都要想插队,每个人有自己想要排的位置(想排第几个人的后面)和自己的编号,求最终每个人的位置。
思路:这题思路是最重要的,至于怎样实现有很多种方法;这题可以变为从最后一个人开始往前算,因为这样算出来就是最终位置了,然后问题就可以转为每个人排第几个空位了。。这样就可以用线段树或树状数组实现了,我用了三种方法实现,第一种是自己想的,也是最挫的,第二第三种是参考别人思路的
1.树状数组 + 二分
复杂度O(nlog^2n)
#include <cstdio>
const int N = 300010;
int n, pos[N], idx[N];
struct BIT{
int sum, idx;
}arr[N];
inline int lowbit(int x){
return x & (-x);
}
void update(int loc, int val, int idxx){
arr[loc].idx = idxx;
while(loc <= n){
arr[loc].sum += val;
loc += lowbit(loc);
}
}
int query(int loc){
int res = 0;
while(loc){
res += arr[loc].sum;
loc -= lowbit(loc);
}
return res;
}
int BSearch(int l, int r, int val){
int mid;
while(l < r){
mid = (l + r) >> 1;
int sum = query(mid);
if(sum < val)
l = mid + 1;
else
r = mid;
}
return l;
}
int main(){
while(~scanf("%d", &n)){
int i;
for(i = 1;i <= n;i++)
arr[i].sum = 0;
for(i = 1;i <= n;i++)
update(i, 1, 0);
for(i = 1;i <= n;i++)
scanf("%d%d", &pos[i], &idx[i]);
for(i = n;i >= 1;i--){
int loc = BSearch(1, n, pos[i] + 1);
update(loc, -1, idx[i]);
}
for(i = 1;i <= n;i++)
printf("%d%c", arr[i].idx, i != n?' ':'\n');
}
return 0;
}
2.线段树
复杂度O(nlogn)
#include <cstdio>
const int N = 200010;
int n, pos[N], val[N], ans[N];
struct segTree{
int lc, rc, sum, idx;
}arr[N * 4];
void pushUp(int idx){
arr[idx].sum = arr[idx * 2].sum + arr[idx * 2 + 1].sum;
}
void build(int idx, int l, int r){
arr[idx].lc = l, arr[idx].rc = r;
if(l == r){
arr[idx].sum = 1;
arr[idx].idx = l;
return ;
}
int mid = (l + r) >> 1;
build(idx * 2, l, mid);
build(idx * 2 + 1, mid + 1, r);
pushUp(idx);
}
void insert(int idx, int loc, int values){
arr[idx].sum--;
if(arr[idx].lc == arr[idx].rc){
ans[arr[idx].lc] = values;
return ;
}
if(arr[idx * 2].sum >= loc)
insert(idx * 2, loc, values);
else{
loc -= arr[idx * 2].sum;
insert(idx * 2 + 1, loc, values);
}
}
int main(){
while(~scanf("%d", &n)){
int i;
build(1, 1, n);
for(i = 1;i <= n;i++)
scanf("%d%d", &pos[i], &val[i]);
for(i = n;i >= 1;i--)
insert(1, pos[i] + 1, val[i]);
for(i = 1;i <= n;i++)
printf("%d%c", ans[i], i != n?' ':'\n');
}
return 0;
}
3.树状数组的高端应用。。
时间复杂度:O(nlogn) 空间复杂度:O(n)
#include <cstdio>
const int N = 200010;
int pos[N], val[N], n, ans[N], bits[N];
inline int lowbit(int x){
return x & (-x);
}
void initiBIT(){
for(int i = 1;i <= n;i++)
bits[i] = lowbit(i);
}
void update(int loc){
while(loc <= n){
bits[loc]--;
loc += lowbit(loc);
}
}
int query(int loc){
int ans = 0, sum = 0, i;
for (i = 18; i >= 0; i--){
ans += (1 << i);
if (ans >= n || sum + bits[ans] >= loc)
ans -= (1 << i);
else
sum += bits[ans];
}
return ans + 1;
}
int main(){
while(~scanf("%d", &n)){
int i;
initiBIT();
for(i = 1;i <= n;i++)
scanf("%d%d", &pos[i], &val[i]);
for(i = n;i >= 1;i--){
int loc = query(pos[i] + 1);
ans[loc] = val[i];
update(loc);
}
for(i = 1;i <= n;i++)
printf("%d%c", ans[i], i != n?' ':'\n');
}
return 0;
}