Queue (HDU - 5493,树状数组 + 二分 || 线段树)

本文解析了HDU-5493队列问题,通过求最小字典序来确定队列中人员的排列。利用树状数组与二分查找或线段树的方法解决了这一问题,并提供了完整的代码实现。

一.题目链接:

HDU-5493

二.题目大意:

有 n 个人排队,身高各不相同.

给出每个人的身高,以及队中他前面比他高或者后面比他高的人数.

若此队伍存在,则输出最小字典序的队伍排列.

否则,输出 "impossible".

三.分析:

因为是求最小字典序,所以先对身高排序,之后再向队中加人.

假设第 i (1 ≤ i ≤ n) 个人的身高为 h,队中他前面比他高或者后面比他高的人数为 k.

则有两个位置可供他插入.

① 队中他前面比他高的人数为 k:则插入的位置应为从前往后的第 k + 1 个空位.

① 队中他后面比他高的人数为 k:则插入的位置应为从前往后的第 n - i - k + 1 个空位.

又因为要求最小字典序

所以第 i 个人所插入的位置应为 min(k+ 1, n - i - k + 1).

现在问题分解为了求第 x 个空位的索引.

有两种方法解决.

1 表示空位,0 表示已有人,

① 树状数组 + 二分:树状数组区间求和当做 check()函数,二分每个人的位置,之后再单点更新.

② 线段树:查询第 x 个空位的下标,之后再单点更新.

现在考虑什么情况是有矛盾的.

易得:第 i 个人前面的空位不足 k 且 后面的空位也不足 k.

即:k + i > n.

四.代码实现:

①树状数组 + 二分

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long int
using namespace std;

const int M = (int)1e5;
const int inf = 0x3f3f3f3f;

struct node
{
    int k;
    int h;
}s[M + 5];

int n;
int h[M + 5];
int c[M + 5];

bool cmp(node a, node b)
{
    return a.h < b.h;
}

int lowbit(int x)
{
    return x & (-x);
}

void update(int x, int v)
{
    for(int i = x; i <= n; i += lowbit(i))
        c[i] += v;
}

int sum(int x)
{
    int ans = 0;
    for(int i = x; i > 0; i -= lowbit(i))
        ans += c[i];
    return ans;
}

int binary1(int i)
{
    int l = 1;
    int r = n;
    while(l < r)
    {
        int mid = (l + r) >> 1;
        if(sum(mid) < s[i].k + 1)
            l = mid + 1;
        else
            r = mid;
    }
    return r;
}

int binary2(int i)
{
    int l = 1;
    int r = n;
    while(l < r)
    {
        int mid = (l + r + 1) >> 1;
        if(sum(n) - sum(mid - 1) < s[i].k + 1)
            r = mid - 1;
        else
            l = mid;
    }
    return r;
}

int main()
{
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ++ca)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            scanf("%d %d", &s[i].h, &s[i].k);
        sort(s + 1, s + n + 1, cmp);
        memset(c, 0, sizeof(c));
        for(int i = 1; i <= n; ++i)
            update(i, 1);
        bool flag = 1;
        for(int i = 1; i <= n; ++i)
        {
            if(i + s[i].k > n)
            {
                flag = 0;
                break;
            }
            int pos = min(binary1(i), binary2(i));
            h[pos] = s[i].h;
            update(pos, -1);
        }
        printf("Case #%d: ", ca);
        if(flag)
        {
            for(int i = 1; i <= n; ++i)
                printf("%d%c", h[i], i == n ? '\n' : ' ');
        }
        else
            printf("impossible\n");
    }
    return 0;
}

② 线段树

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long int
using namespace std;

const int M = (int)1e5;
const int inf = 0x3f3f3f3f;

int n;

struct node1
{
    int h;
    int k;
} s[M + 5];

int height[M + 5];
int tree[M * 4 + 5];

bool cmp(node1 a, node1 b)
{
    return a.h < b.h;
}

void push_up(int k)
{
    tree[k] = tree[lc] + tree[rc];
}

void build(int k, int l, int r)
{
    if(l == r)
    {
        tree[k] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(lc, l, mid);
    build(rc, mid + 1, r);
    push_up(k);
}

int query(int k, int l, int r, int a, int b)
{
    if(l >= a && r <= b)
        return tree[k];
    int mid = (l + r) >> 1;
    int ans = 0;
    if(a <= mid)
        ans += query(lc, l, mid, a, b);
    if(mid < b)
        ans += query(rc, mid + 1, r, a, b);
    return ans;
}

void update(int k, int l, int r, int num, int h)
{
    if(l == r)
    {
        tree[k] = 0;
        height[l] = h;
        return;
    }
    int mid = (l + r) >> 1;
    if(num <= tree[lc])
        update(lc, l, mid, num, h);
    else
        update(rc, mid + 1, r, num - tree[lc], h);
    push_up(k);
}

int main()
{
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ++ca)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            scanf("%d %d", &s[i].h, &s[i].k);
        build(1, 1, n);
        sort(s + 1, s + n + 1, cmp);
        bool flag = 1;
        for(int i = 1; i <= n; ++i)
        {
            if(i + s[i].k > n)
            {
                flag = 0;
                break;
            }
            update(1, 1, n, min(s[i].k + 1, n - i - s[i].k + 1), s[i].h);
        }
        printf("Case #%d: ", ca);
        if(flag)
        {
            for(int i = 1; i <= n; ++i)
                printf("%d%c", height[i], i == n ? '\n' : ' ');
        }
        else
            printf("impossible\n");
    }
    return 0;
}

 

### 三个月备考百度之星比赛的算法训练计划(一个月冲刺版) 百度之星比赛作为国内高水平的编程竞赛之一,对选手的算法基础、编码能力以及问题建模能力有较高要求。对于不同起点的参赛者,应根据自身情况制定相应的学习和训练策略。若为大二及以上且基础较弱的学生,建议慎重投入过多时间以避免“打铁”风险[^1]。但若已有一定算法基础或目标是参与并取得中等以上成绩,则可参考以下为期一个月的高强度训练计划。 --- ### 第一周:夯实核心算法基础 重点掌握数据结构与基础算法的核心内容,确保能在实际题目中快速应用。 - **数据结构**- 线性结构:数组、链表、栈、队列、双端队列 - 树状结构:堆(优先队列)、并查集、线段树(初步了解) - 哈希表与字典树(Trie) - **排序与查找**- 快速排序、归并排序、计数排序 - 二分查找(包括上下界、浮点数精度处理) - **图论基础**- 图的表示方式(邻接矩阵、邻接表) - 深度优先搜索(DFS)与广度优先搜索(BFS) - 拓扑排序、强连通分量(Kosaraju 或 Tarjan) ```python # BFS模板示例 from collections import deque def bfs(graph, start): visited = set() queue = deque([start]) visited.add(start) while queue: node = queue.popleft() for neighbor in graph[node]: if neighbor not in visited: visited.add(neighbor) queue.append(neighbor) ``` --- ### 第二周:动态规划与贪心策略强化 该阶段重点提升对状态设计和转移的理解,掌握常见DP模型,并熟悉贪心策略的适用条件。 - **动态规划类型**- 背包问题(01背包、完全背包) - 区间DP(如石子合并) - LIS/LCS/最大子数组和等经典问题 - 数位DP(可选) - **贪心策略**- 活动选择、区间调度、哈夫曼编码 - 贪心与DP结合题型练习 ```python # 最长递增子序列(LIS)DP解法 def lis(nums): n = len(nums) dp = [1] * n for i in range(n): for j in range(i): if nums[i] > nums[j]: dp[i] = max(dp[i], dp[j] + 1) return max(dp) ``` --- ### 第三周:图论进阶与数学优化 深入掌握图论中的最短路径、最小生成树、网络流等内容,并加强数论与组合数学的应用能力。 - **图论进阶**- Dijkstra、Bellman-Ford、SPFA、Floyd-Warshall - Kruskal、Prim(MST) - 网络流(Edmonds-Karp、Dinic) - **数论与组合数学**- 快速幂、欧几里得算法、扩展欧几里得 - 素数筛法(埃氏筛、线性筛) - 排列组合、卡特兰数、卢卡斯定理(可选) ```python # 快速幂算法 def fast_pow(a, b, mod): res = 1 a %= mod while b: if b & 1: res = res * a % mod a = a * a % mod b >>= 1 return res ``` --- ### 第四周:真题实战与模拟训练 最后一周集中进行历年百度之星真题训练与模拟赛,提升临场应变能力和代码调试效率。 - **每日安排**- 上午做一套历年真题(限时3小时) - 下午复盘题解,整理思路与优化代码实现 - 晚上针对当天未掌握的知识点进行专项补漏 - **模拟赛平台推荐**- HDU OJ(包含大量百度之星原题) - 牛客网、LeetCode Contest、Codeforces(CF Div.2- **注意事项**- 强化代码规范与边界条件处理 - 提高读题速度与理解准确性 - 学会合理分配时间,不被难题拖累整体得分 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值