• HDU 2665 && POJ 2104(主席树)


    http://poj.org/problem?id=2104

    对权值进行建树(这个时候树的叶子是数组b的有序数列),然后二分查找原数列中每个数在有序数列中的位置(即第几小),对每一个前缀[1,i]建一棵树。用到前缀和的思想,区间第k小就可以直接查找T[r] - T[l-1]区间内第k小的数。如果对每一个前缀建一棵树,无疑会MLE,这个时候用到主席树。

    主席树在我的理解:在更新的时候,只有一棵树中的一条路径有改变,这个时候我们只要修改改变的那条路径,而不是重新建一棵树。要做的是直接把上一个版本的线段树给现在的版本,然后对现在版本进行更新。

    睡觉前不要打代码..做了一个晚上主席树的梦.

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <string>
     5 #include <cmath>
     6 #include <iostream>
     7 #include <stack>
     8 using namespace std;
     9 #define N 100010
    10 
    11 /*
    12 主席树
    13 http://www.bilibili.com/video/av4619406/
    14 http://www.cnblogs.com/Empress/p/4652449.html
    15 题意:在一堆数里面有m个询问,每个询问求区间[l,r]里面的第k小的数是哪个.
    16 要认识权值线段树:在以节点i为根的树中,[1,i]区间内包含的数的个数.
    17 */
    18 struct node
    19 {
    20     int l, r, sum;//sum储存的就是权值
    21 }tree[N*40];
    22 int root[N];//储存根节点
    23 int a[N], b[N], tot;
    24 
    25 void update(int pre, int &now, int x, int l, int r)
    26 {
    27     tree[++tot] = tree[pre];//把上一个版本的线段树给现在的版本,然后对要修改的那条链进行更新
    28     now = tot;
    29     tree[now].sum++;//因为插入了新的数,所以要更新+1
    30     if(l == r) return ;
    31     int m = (l + r) >> 1;
    32     if(x <= m) update(tree[pre].l, tree[now].l, x, l, m);
    33     else update(tree[pre].r, tree[now].r, x, m + 1, r);
    34 }
    35 
    36 int query(int left, int right, int k, int l, int r)
    37 {
    38     if(l == r) return l;
    39     int m = (l + r) >> 1;
    40     int sum = tree[tree[right].l].sum - tree[tree[left].l].sum;//如果左子树已经有k个数,那么答案就在左边
    41     if(k <= sum) return query(tree[left].l, tree[right].l, k, l, m);
    42     else return query(tree[left].r, tree[right].r, k - sum, m + 1, r);
    43 }
    44 
    45 int main()
    46 {
    47 //    int t;
    48 //    scanf("%d", &t);
    49 //    while(t--) {
    50         int n, m;
    51         scanf("%d%d", &n, &m);
    52         tot = 0;
    53         for(int i = 1; i <= n; i++) {
    54             scanf("%d", &a[i]);
    55             b[i] = a[i];
    56         }
    57         sort(b + 1, b + 1 + n);
    58         int cnt = unique(b + 1, b + 1 + n) - b - 1;
    59         for(int i = 1; i <= n; i++) {
    60             a[i] = lower_bound(b + 1, b + 1 + cnt, a[i]) - b; //二分找到a[i]的位置
    61 //            printf("QQQQQ
    ");
    62             update(root[i-1], root[i], a[i], 1, cnt); //root[i-1]表示上一个版本的线段树
    63         }
    64         for(int i = 1; i <= m; i++) {
    65             int l, r, k;
    66             scanf("%d%d%d", &l, &r, &k);
    67             int ans = query(root[l-1], root[r], k, 1, cnt); //ans是第k个数的位置
    68             printf("%d
    ", b[ans]); //因为询问的是哪个数,所以要b[ans]
    69         }
    70 //    }
    71     return 0;
    72 }
  • 相关阅读:
    监狱生活Felon
    [转]ios面试题收集(二)
    (转载)Xfermodes的扩展应用 图像擦除和还原效果
    (转)检测iPhone/iPod Touch/iPad设备类型
    iphone 推送服务Apple Push Notification Service
    [转]ios面试题收集(四)
    [转]ios面试题收集(五)
    [转]ios面试题收集(一)
    【很强大的ios代码大全】代码例子区全区搜索索引
    ios开发工程师常见面试题汇总
  • 原文地址:https://www.cnblogs.com/fightfordream/p/5824155.html
Copyright © 2020-2023  润新知