zoukankan      html  css  js  c++  java
  • ACM/ICPC 之 数据结构-线段树思想(POJ2182,含O(n^2)插入式解法)

    这道题在一定程度上体现了线段树的一种用法,解决的问题是:对于总计n个元素的第i个元素,已知其在[1,i]上部分序列的排名,求第i个元素在所有n个元素中的排名。

    当然这道题数据比较水,所以用O(n^2)的直接解法也可以解出,在这里,我也给出自己的O(n^2)解法。


      题目大意:

        n头乱序的牛排列在一行,每头牛都有一个牌号(1-n),现在知道所有牛此前有多少头牛的牌号比该牛的牌号要小,求每头牛的牌号。

      直接解法(插入式):

        从前向后遍历每一个数据,每次都进行一次插入。

        具体来说:例如对于(1,0,1)这样的序列,我们先设brand[1] = 1。

          由第一个数据(1)有brand[2] = 2    ————有排名为:(1,2)

          由第二个数据(0)有brand[3] = 1,此时遍历此前所有元素,查询到>=brand[3]则加一个排名,得到brand[1] = 2,brand[2] = 3;  ——排名(2,3,1)

          由第三个数据(1)有brand[4] = 2,此时遍历此前元素,参照上面的方法,得到brand[1] = 3,brand[2] = 4;  ——(3,4,1,2)

        那么最后能够得到排名(3,4,1,2);

      Code如下:

     1 //普通的O(n^2)算法-直接的想法
     2 //n头牛,已知第i头牛在1-i部分序列的排名,求所有牛的牌号(排名)
     3 //Memory: 236K Time:375Ms
     4 #include<iostream>
     5 #include<cstdio>
     6 #include<cstring>
     7 using namespace std;
     8 #define MAX 8005
     9 int n;    //cow头量
    10 int small[MAX];    //比第i头cow靠前但牌号较小的cow头量
    11 int brand[MAX];    //牌号
    12 int main()
    13 {
    14     scanf("%d", &n);
    15     brand[1] = 1;
    16     for (int i = 2; i <= n; i++)
    17     {
    18         scanf("%d", &small[i]);
    19         brand[i] = small[i] + 1;
    20         if (small[i] + 1 != i)    //不是排在最后
    21         {
    22             for (int j = 1; j < i; j++)
    23             {
    24                 if (brand[j] >= brand[i])    //>=该序号则+1
    25                     brand[j]++;
    26             }
    27         }
    28     }
    29     for (int i = 1; i <= n; i++)
    30         printf("%d
    ", brand[i]);
    31     return 0;
    32 }
    插入式-解法

      线段树解法:

        大体想法就是:用线段树存储一个从1-n的顺序排名,将数据从后向前遍历,每次遍历到某一个位置时,假设原数据为s[],那么对于s[i],其在1-i的排名就是s[i]+1,那么在线段树中将[s[i]+1,s[i]+1]区间的sum置为0(减去1)。也就是删去s[i]+1这个排名,这样排名的整体规模就缩小了一个单位,即原为n个元素排名,现在是n-1个元素排名(第s[i]+1排名被删去),并保留原排名数值不变。

        这样不断遍历,不断缩减排名的规模就可以依次反向得到该乱序的牛的牌号,然后顺序输出牌号即可

      Code如下:

      

     1 //线段树
     2 //n头牛,已知第i头牛在1-i部分序列的排名,求所有牛的牌号(排名)
     3 //Memory: 432K Time:47Ms
     4 #include<iostream>
     5 #include<cstdio>
     6 #include<cstring>
     7 using namespace std;
     8 #define MAX 8005
     9 int n;    //cow头量
    10 int small[MAX];    //比第i头cow靠前但牌号较小的cow头量
    11 int brand[MAX];    //牌号
    12 //Brand interval数组
    13 struct Brands{
    14     int l, r;    //牌号区间
    15     int sum;    //头数
    16 }tree[4*MAX];
    17 /*从x开始搭建interval tree*/
    18 void build(int x,int l,int r)
    19 {
    20     tree[x].l = l;
    21     tree[x].r = r;
    22     if (l == r){
    23         tree[x].sum = 1;
    24         return;
    25     }
    26     int mid = (l + r) / 2;
    27     build(2 * x, l, mid);        //left son
    28     build(2 * x + 1, mid + 1, r);    //right son
    29     tree[x].sum = tree[2 * x].sum + tree[2 * x + 1].sum;
    30 }
    31 int query(int x, int v)
    32 {
    33     tree[x].sum--;
    34     // Hit!
    35     if (tree[x].l == tree[x].r)
    36         return tree[x].l;
    37     if (v <= tree[2 * x].sum)    //<=左结点未删减序列数量
    38         query(2 * x, v);
    39     else query(2 * x + 1, v - tree[2 * x].sum);
    40 }
    41 int main()
    42 {
    43     scanf("%d", &n);
    44     for (int i = 2; i <= n; i++)
    45         scanf("%d", &small[i]);
    46     small[1] = 0;
    47     build(1, 1, n);
    48     for (int i = n; i >= 1; i--)
    49         brand[i] = query(1, small[i] + 1);    //牌号
    50     for (int i = 1; i <= n; i++)
    51         printf("%d
    ", brand[i]);
    52     return 0;
    53 }
    线段树-解法

    他坐在湖边,望向天空,她坐在对岸,盯着湖面
  • 相关阅读:
    JavaFX 1.2 SDK 发布,增加 Linux 及 OpenSolaris 支持
    JSF 2.0 通过最终投票
    NetBeans 时事通讯(刊号 # 57 May 27, 2009)
    “C语言” 读书札记(六)之[Linux下C语言编程环境Make命令和Makefile] 川山甲 博客园
    [转]宽字符的介绍
    【语法回顾】C++STL:string类型 ATP_ 博客园
    Using the C/C++ Garbage Collection Library, libgc
    Makefile学习笔记 我的CPP之路 C++博客
    伍迷创意随想集 之 杯具拥有个性,个性成就杯具 伍迷 博客园
    知哈希算法——找出相似的图片
  • 原文地址:https://www.cnblogs.com/Inkblots/p/4921890.html
Copyright © 2011-2022 走看看