poj 2828 Buy Tickets(树状数组 | 线段树)

题目链接:poj 2828 Buy Tickets

题目大意:给定N,表示有个人,给定每个人站入的位置,以及这个人的权值,现在按队列的顺序输出每个人的权值。

解题思路:第K大元素,很巧妙,将人入队的顺序倒过来看,就是纯第K大问题,然后用树状数组还是线段树就都可以做了。

C++ 线段树

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 200005;

#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)+1)

struct Node {
    int l, r, s;
    void set(int l, int r, int s) {
        this->l = l;
        this->r = r;
        this->s = s;
    }
}nd[maxn * 4];

int N, val[maxn], pos[maxn], rec[maxn];

void build (int u, int l, int r) {
    nd[u].set(l, r, r - l + 1);

    if (l == r)
        return ;
    int mid = (l + r) / 2;
    build(lson(u), l, mid);
    build(rson(u), mid + 1, r);
}

int query (int u, int x) {
    nd[u].s--;

    if (nd[u].l == nd[u].r)
        return nd[u].l;

    if (nd[lson(u)].s >= x)
        return query(lson(u), x);
    else
        return query(rson(u), x - nd[lson(u)].s);
}

int main () {
    while (scanf("%d", &N) == 1) {
        build(1, 0, N - 1);
        for (int i = 0; i < N; i++)
            scanf("%d%d", &pos[i], &val[i]);

        for (int i = N - 1; i >= 0; i--)
            rec[query(1, pos[i] + 1)] = i;

        printf("%d", val[rec[0]]);
        for (int i = 1; i < N; i++)
            printf(" %d", val[rec[i]]);
        printf("\n");
    }
    return 0;
}
C++ 树状数组

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 200005;
#define lowbit(x) ((x)&(-x))

int N, fenw[maxn], pos[maxn], val[maxn], rec[maxn];

void add (int x, int v) {
    while (x <= N) {
        fenw[x] += v;
        x += lowbit(x);
    }
}

int find (int x) {
    int p = 0, s = 0;
    for (int i = 20; i >= 0; i--) {
        p += (1<<i);
        if (p > N || s + fenw[p] >= x)
            p -= (1<<i);
        else
            s += fenw[p];
    }
    return p + 1;
}

int main () {
    while (scanf("%d", &N) == 1) {
        memset(fenw, 0, sizeof(fenw));
        for (int i = 1; i <= N; i++) {
            add(i, 1);
            scanf("%d%d", &pos[i], &val[i]);
        }

        for (int i = N; i; i--) {
            int tmp = find(pos[i] + 1);
            rec[tmp] = i;
            add(tmp, -1);
        }

        for (int i = 1; i <= N; i++)
            printf("%d%c", val[rec[i]], i == N ? ‘\n‘ : ‘ ‘);
    }
    return 0;
}

时间: 2024-08-09 06:33:48

poj 2828 Buy Tickets(树状数组 | 线段树)的相关文章

POJ 2828 Buy Tickets(排队问题,线段树应用)

POJ 2828 Buy Tickets(排队问题,线段树应用) ACM 题目地址:POJ 2828 Buy Tickets 题意: 排队买票时候插队. 给出一些数对,分别代表某个人的想要插入的位置Pos_i和他的Val_i,求出最后的队列的val顺序. 分析: 也是一道非常巧妙的题目. 刚開始天真的以为sort一下即可了.wa了一发后发现我错了... 原来能够非常巧妙的用线段树做.因为某个人想要插入posi位置,插入后他就在posi位置上了,可是可能其它人会插到他前面来,他的位置就会变成[在他

POJ 2827 Buy Tickets(排队问题,线段树应用)

POJ 2827 Buy Tickets(排队问题,线段树应用) ACM 题目地址:POJ 2827 Buy Tickets 题意: 排队买票时候插队. 给出一些数对,分别代表某个人的想要插入的位置Pos_i和他的Val_i,求出最后的队列的val顺序. 分析: 也是一道很巧妙的题目. 刚开始天真的以为sort一下就行了.wa了一发后发现我错了... 原来可以很巧妙的用线段树做.由于某个人想要插入posi位置,插入后他就在posi位置上了,但是可能其他人会插到他前面来,他的位置就会变成[在他后面

hdu 1166 树状数组 线段树

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 51177    Accepted Submission(s): 21427 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

hdu1394(枚举/树状数组/线段树单点更新&amp;区间求和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 或 -1, 交换两个不相邻数 a, b, 逆序数 += 两者间大于 a 的个数 - 两者间小于 a 的个数: 所以只要求出初始时的逆序对数,就可以推出其余情况时的逆序对数.对于求初始逆序对数,这里 n 只有 5e3,可以直接暴力 / 树状数组 / 线段树 / 归并排序: 代码: 1.直接暴力 1

HDU 1394 Minimum Inversion Number 树状数组&amp;&amp;线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少 逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #i

HDU 1166 敌兵布阵 (树状数组&#183;线段树)

题意  中文 动态区间和问题   只会更新点  最基础的树状数组 线段树的应用 树状数组代码 #include <bits/stdc++.h> using namespace std; const int N = 50005; int c[N], n, m; void add(int p, int x) { while(p <= n) c[p] += x, p += p & -p; } int getSum(int p) { int ret = 0; while(p > 0

Curious Robin Hood(树状数组+线段树)

1112 - Curious Robin Hood    PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 64 MB Robin Hood likes to loot rich people since he helps the poor people with this money. Instead of keeping all the money together he does another tri

士兵杀敌(四)(树状数组+线段树)

士兵杀敌(四) 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个人身上,这样,有时候,计算他们中的哪一个人到底有多少军功就是一个比较困难的事情,军师小工的任务就是在南将军询问他某个人的军功的时候,快速的报出此人的军功,请你编写一个程序来帮助小工吧. 假设起始时所有人的军功都是0. 输入

Color the ball(树状数组+线段树)

Color the ball Time Limit : 9000/3000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 3   Accepted Submission(s) : 1 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b