zoukankan      html  css  js  c++  java
  • [BZOJ3932] [CQOI2015]任务查询系统(主席树 || 树状数组 套 主席树 + 差分 + 离散化)

    传送门

    看到这个题有个很暴力的想法,

    可以每一个时间点都建一颗主席树,主席树上叶子节点 i 表示优先级为 i 的任务有多少个。

    当 x 到 y 有个优先级为 k 的任务时,循环 x 到 y 的每个点,都插入一个 k。

    当然这样肯定完蛋。

    x 到 y 插入一个优先级为 k 的任务?

    想到差分,给时间点为 x 的主席树插入 k,给时间点为 y + 1 的主席树插入 -k。

    那么求一个树状数组的前缀和就好了。

    前缀和?

    用树状数组优化。

    这样就可以用 树状数组 套 主席树 来做。

    ——代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #define LL long long
     5 
     6 const int MAXN = 1e5 + 5, p = 200;
     7 int n, m, cnt, t;
     8 int S[MAXN], E[MAXN], P[MAXN], num[MAXN], root[MAXN], id[MAXN], q[21], s[MAXN * p], ls[MAXN * p], rs[MAXN * p];
     9 LL sum[MAXN * p], pre = 1;
    10 
    11 inline int read()
    12 {
    13     int x = 0, f = 1;
    14     char ch = getchar();
    15     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    16     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    17     return x * f;
    18 }
    19 
    20 inline bool cmp(int x, int y)
    21 {
    22     return P[x] < P[y];
    23 }
    24 
    25 inline void insert(int last, int &now, int l, int r, int x, int v1, int v2)
    26 {
    27     if(!now) now = ++cnt;
    28     sum[now] = sum[last] + v1, s[now] = s[last] + v2, ls[now] = ls[last], rs[now] = rs[last];
    29     if(l == r) return;
    30     int mid = (l + r) >> 1;
    31     if(x <= mid) insert(ls[last], ls[now], l, mid, x, v1, v2);
    32     else insert(rs[last], rs[now], mid + 1, r, x, v1, v2);
    33 }
    34 
    35 inline LL query(int l, int r, int k)
    36 {
    37     if(l == r)
    38     {
    39         LL t2 = 0;
    40         for(int i = 1; i <= t; i++) t2 += sum[q[i]];
    41         return t2;
    42     }
    43     LL t2 = 0;
    44     int t1 = 0, mid = (l + r) >> 1;
    45     for(int i = 1; i <= t; i++) t1 += s[ls[q[i]]], t2 += sum[ls[q[i]]];
    46     if(k <= t1)
    47     {
    48         for(int i = 1; i <= t; i++) q[i] = ls[q[i]];
    49         return query(l, mid, k);
    50     }
    51     else
    52     {
    53         for(int i = 1; i <= t; i++) q[i] = rs[q[i]];
    54         return t2 + query(mid + 1, r, k - t1);
    55     }
    56 }
    57 
    58 int main()
    59 {
    60     int i, j, x, a, b, c;
    61     LL k;
    62     n = read();
    63     m = read();
    64     for(i = 1; i <= n; i++)
    65     {
    66         S[i] = read();
    67         E[i] = read();
    68         P[i] = read();
    69         id[i] = i;
    70     }
    71     std::sort(id + 1, id + n + 1, cmp);
    72     for(i = 1; i <= n; i++) num[id[i]] = i;
    73     for(i = 1; i <= n; i++)
    74     {
    75         for(j = S[i]; j <= n; j += j & -j) insert(root[j], root[j], 1, n, num[i], P[i], 1);
    76         for(j = E[i] + 1; j <= n; j += j & -j) insert(root[j], root[j], 1, n, num[i], -P[i], -1);
    77     }
    78     for(i = 1; i <= m; i++)
    79     {
    80         scanf("%d %d %d %d", &x, &a, &b, &c);
    81         k = 1 + (LL)(a * pre + b) % c;
    82         t = 0;
    83         for(j = x; j; j -= j & -j) q[++t] = root[j];
    84         pre = query(1, n, k);
    85         printf("%lld
    ", pre);
    86     }
    87     return 0;
    88 }
    View Code

    其实如果按照时间排序的话,依次插入主席树,就可以维护前缀和,而省去了树状数组的麻烦。

    然后注意的是每个时间点有可能会有多颗主席树。

    ——代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #define LL long long
     5 
     6 const int MAXN = 1e5 + 5;
     7 int n, m, tot, size, cnt;
     8 int num[MAXN], id[MAXN], v[MAXN], ls[MAXN * 40], rs[MAXN * 40], s[MAXN * 40], root[MAXN];
     9 LL pre = 1, sum[MAXN * 40];
    10 struct node
    11 {
    12     int S, val, type, num;
    13 }p[MAXN * 2];
    14 
    15 inline int read()
    16 {
    17     int x = 0, f = 1;
    18     char ch = getchar();
    19     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    20     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    21     return x * f;
    22 }
    23 
    24 inline bool cmp(node x, node y)
    25 {
    26     return x.S < y.S;
    27 }
    28 
    29 inline void insert(int &now, int l, int r, int x, int v1, int v2)
    30 {
    31     ++cnt;
    32     sum[cnt] = sum[now] + v1;
    33     s[cnt] = s[now] + v2;
    34     ls[cnt] = ls[now];
    35     rs[cnt] = rs[now];
    36     now = cnt;
    37     if(l == r) return;
    38     int mid = (l + r) >> 1;
    39     if(x <= mid) insert(ls[now], l, mid, x, v1, v2);
    40     else insert(rs[now], mid + 1, r, x, v1, v2);
    41 }
    42 
    43 inline LL query(int now, int l, int r, int x)
    44 {
    45     if(l == r) return sum[now];
    46     int mid = (l + r) >> 1;
    47     if(x <= s[ls[now]]) return query(ls[now], l, mid, x);
    48     else return sum[ls[now]] + query(rs[now], mid + 1, r, x - s[ls[now]]);
    49 }
    50 
    51 inline bool cmp1(int x, int y)
    52 {
    53     return v[x] < v[y];
    54 }
    55 
    56 int main()
    57 {
    58     int i, j, x, y, z, a;
    59     LL k;
    60     n = read();
    61     m = read();
    62     for(i = 1; i <= n; i++)
    63     {
    64         x = read();
    65         y = read();
    66         v[i] = read();
    67         num[i] = i;
    68         p[++tot].S =      x, p[tot].val =  v[i], p[tot].type =  1;
    69         p[++tot].S = y + 1, p[tot].val = -v[i], p[tot].type = -1;
    70     }
    71     std::sort(num + 1, num + n + 1, cmp1);
    72     for(i = 1; i <= n; i++) id[num[i]] = i;
    73     /*std::sort(v + 1, v + n + 1);
    74     size = std::unique(v + 1, v + n + 1) - (v + 1);
    75     for(i = 1; i <= n; i++) id[i] = std::lower_bound(v + 1, v + size + 1, id[i]) - v;*/
    76     tot = 0;
    77     for(i = 1; i <= n; i++) p[++tot].num = id[i], p[++tot].num = id[i];
    78     std::sort(p + 1, p + tot + 1, cmp);
    79     j = 1;
    80     for(i = 1; i <= m; i++)
    81     {
    82         root[i] = root[i - 1];
    83         while(p[j].S == i)
    84             insert(root[i], 1, n, p[j].num, p[j].val, p[j].type), j++;
    85     }
    86     for(i = 1; i <= m; i++)
    87     {
    88         a = read();
    89         x = read();
    90         y = read();
    91         z = read();
    92         k = 1 + (LL)(x * pre + y) % z;
    93         printf("%lld
    ", pre = query(root[a], 1, n, k));
    94     }
    95     return 0;
    96 }
    View Code

    最后,需要注意对动态开点的理解。

    以及,这个题是对优先级离散化,优先级有可能有相同的,但是离散化却不去重,这就会使得相同数值会是递增的一段数。

    为什么不去重?

    这是为了方便找前 k 个。

    如果去重,有可能 query 时,找到一个叶子节点它的个数会超过一个,比如说 5 个,而只要找 3 个,那样处理就比较麻烦,还得再记录每个叶子节点的优先级。

    不去重就保证了每个叶节点的个数只有一个,而对于答案没有影响。

  • 相关阅读:
    POJ
    POJ 3268 Silver Cow Party
    POJ 3046
    HDU 2089
    MVC树控件,mvc中应用treeview,实现复选框树的多层级表单控件
    研发产品经理培训什么?(摘抄)
    设计模式简要分析说明与归纳总结
    设计模式(十四)模板方法模式(Template Pattern)
    设计模式(十三)代理模式(Proxy Pattern)
    设计模式(十二)享元模式(Flyweight Pattern)
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6875426.html
Copyright © 2011-2022 走看看