Buy Tickets
Sample Input
4 0 77 1 51 1 33 2 69 4 0 20523 1 19243 1 3890 0 31492
Sample Output
77 33 69 51 31492 20523 3890 19243
题意: 插队问题,先给一个n, 然后又n个人进行排队, 左边的数是这个人排队后的位置, 后面的人可能插队, 比如第一个人是第0个位置,第二个人的排队后位置也是0 那么第二个人就将插在第一个人的前面, 变成 第二个人的位置是0, 第一个人的位置是1,右边的数是这个人的分数.也可以说是标记. 最后依次输出从小到大位置的人的标记
题解: 这是线段树的问题. 首先关键是 逆序插入, 后来的人不会随前面的人而改动自己的位置
要将某个人插在第n个位置上,如果这个位置没有人,就插入节点,反之,向后移动至第一个空位
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
const int MAXN = 200000;
int pos[MAXN + 100];
int val[MAXN + 100];
int ans[MAXN + 100];
struct Node{
int num;//表示位置空位的数量
int left;
int right;
}node[(MAXN << 2) + 1000];
void build(int L, int R, int rt){
node[rt].left = L;
node[rt].right = R;
if (L == R){
node[rt].num = 1;
return;
}
int mid = (L + R) >> 1;
build(L, mid, rt << 1);
build(mid + 1, R, rt << 1 | 1);
node[rt].num = node[rt << 1].num + node[rt << 1 | 1].num;
}
void update(int n, int val, int rt){//传进来的n表示要插入的位置
if (node[rt].left == node[rt].right){//到这一步说明此处肯定有位置
node[rt].num = 0;
ans[node[rt].left] = val;//记录分数
return;
}
if (node[rt << 1].num >= n) update(n, val, rt << 1);//如果左边的空位数量大于n 就向左走
else update(n - node[rt << 1].num, val, rt << 1 | 1);//如果小于,向右边走n-node[rt<<1](相当于插入右边空位的第n个位置)
node[rt].num = node[rt << 1].num + node[rt << 1 | 1].num;
}
int main(){
int m;
while (scanf("%d", &m) != EOF){
for (int i = 1; i <= m; i++) scanf("%d%d", &pos[i], &val[i]);
build(1, m, 1);
for (int i = m; i >= 1; i--){
update(pos[i] + 1, val[i], 1);//这里的pos可以为0 应与node的下标对应
}
for (int i = 1; i <= m; i++){
if (i != 1) printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
return 0;
}
Queue
Examples
Input
6 10 8 5 3 50 45Output
2 1 0 -1 0 -1Input
7 10 4 6 3 2 8 15Output
4 2 1 0 -1 -1 -1Input
5 10 3 1 10 11Output
1 0 -1 -1 -1
题意: 求 第i个位置和最后一个位置j满足a[i] > a[j], 求两个位置中间的数的个数
题解:, 线段树经典题目 ,求逆序对,我们可以设线段树中存放的是左树和右树的最小值, 那么如果当前查询的值小于右树所存的右树的最小值,那么这个数一定在左树中,在update的时候应该将已经访问过得点都设为INF 这样就可以避免查找到 比 i 小的值
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 100000;
const int INF = 0x3f3f3f3f;
struct Node{
int minn;
int index;
}node[(MAXN << 2) + 100];
int a[MAXN + 100];
int num;
int n;
void pushup(int rt){
node[rt].minn = min(node[rt << 1].minn, node[rt << 1 | 1].minn);
}
void build(int L, int R, int rt){
if (L == R){
node[rt].index = num;
node[rt].minn = a[num++];
return;
}
int mid = (L + R) >> 1;
build(L, mid, rt << 1);
build(mid + 1, R, rt << 1 | 1);
pushup(rt);
}
int query(int position, int L, int R, int rt){
if (L == R){
return node[rt].index;
}
int mid = (L + R) >> 1;
int res = 0;
if (node[rt << 1 | 1].minn < a[position]) return query(position, mid + 1, R, rt << 1 | 1);
else return query(position, L, mid, rt << 1);
}
void update(int position, int L, int R, int rt){
if (L == R){
a[position] = INF;
node[rt].minn = INF;
return;
}
int mid = (L + R) >> 1;
if (position <= mid) update(position, L, mid, rt << 1);
else update(position, mid + 1, R, rt << 1 | 1);
pushup(rt);
}
int main(){
while (scanf("%d", &n) != EOF){
num = 1;
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
build(1, n, 1);
int res;
for (int i = 1; i <= n; i++){
if (i != 1) printf(" ");
int j = query(i, 1, n, 1);
if (j == 1) j = i;
printf("%d", j - i - 1);
update(i, 1, n, 1);
}
printf("\n");
}
return 0;
}