• POJ 2828 Buy Tickets (线段树 单点更新 变形)


    题目链接

    题意:有N个人排队,给出各个人想插队的位置和标识,要求输出最后的序列。

    分析:因为之前的序列会因为插队而变化,如果直接算时间复杂度很高,所以可以用

    线段树逆序插入,把序列都插到最后一层,len记录该区间里还剩余多少位置,插入的时候就插到剩余的第几个位置,

    比如1,2已经插入了,如果再想插入第3个位置,则实际上插入的是5. 因为是逆序的,所以在3之前除了现在的1,2

    还有之前的1,2.

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cstdlib>
     5 #include <algorithm>
     6 const int maxn = 200000+10;
     7 using namespace std;
     8 int n, ans[maxn];
     9 struct node
    10 {
    11     int p, v;
    12 }a[maxn];
    13 struct line
    14 {
    15    int l, r, len; //区间剩余的长度
    16 }tr[4*maxn];
    17 void build(int o, int l, int r)
    18 {
    19     tr[o].l = l; tr[o].r = r;
    20     tr[o].len = r-l+1;
    21     if(l==r) return;
    22     int mid = (l+r)/2;
    23     build(2*o, l, mid);
    24     build(2*o+1, mid+1, r);
    25 }
    26 void update(int o, int p, int v)
    27 {
    28     tr[o].len --;
    29     if(tr[o].l==tr[o].r)
    30     {
    31         ans[tr[o].l] = v;  //ans记录最后一层的值
    32         return;
    33     }
    34     if(p<tr[2*o].len) update(2*o, p, v);
    35     else update(2*o+1, p-tr[2*o].len, v);
    36 }
    37 int main()
    38 {
    39     int i;
    40     while(~scanf("%d", &n))
    41     {
    42         for(i = 0; i < n; i++)
    43         scanf("%d%d", &a[i].p, &a[i].v);
    44         build(1, 0, n-1);
    45         for(i = n-1; i >= 0; i--) //逆序
    46         update(1, a[i].p, a[i].v);
    47 
    48         for(i = 0; i < n-1; i++)
    49         printf("%d ", ans[i]);
    50         printf("%d
    ", ans[i]);
    51     }
    52     return 0;
    53 }
  • 相关阅读:
    最佳调度问题_分支限界法
    运动员最佳配对问题
    最小重量机器设计问题
    实现银行家算法和先进先出算法_对文件读写数据
    n皇后问题_回溯法
    0-1背包_回溯法
    根据前序、中序、后序遍历还原二叉树
    矩阵连乘问题_动态规划
    最长公共子序列_动态规划
    最优二叉查找树_动态规划
  • 原文地址:https://www.cnblogs.com/bfshm/p/3891633.html
Copyright © 2020-2023  润新知