zoukankan      html  css  js  c++  java
  • [BZOJ3110] [Zjoi2013] K大数查询 (树套树)

    Description

      有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
    如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

    Input

      第一行N,M
      接下来M行,每行形如1 a b c或2 a b c

    Output

      输出每个询问的结果

    Sample Input

    2 5
    1 1 2 1
    1 1 2 2
    2 1 1 2
    2 1 1 1
    2 1 2 3

    Sample Output

    1
    2
    1

    HINT

      【样例说明】
      第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1
    的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是
    1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3
    大的数是 1 。‍

      N,M<=50000,N,M<=50000
      a<=b<=N
      1操作中abs(c)<=N
      2操作中c<=Maxlongint

    Source

    Solution

      树套树。。。说难不难,说简单不简单。曾经花了一星期理解内外线段树的关系。。。一直不理解怎么“套”一棵树的

      树套树的一般做法是用两个树形结构,外层代表区间,内层代表该区间下的权值信息或其它的什么

      相当于一个二维矩阵,一维是区间信息一维是权值信息。

      嘛,其实就是外层线段树纪录它对应的内层线段树的节点编号,内层线段树纪录该区间下与某权值范围的的结点信息

      为了省空间,需用动态开点的姿势。在这里给各位提个醒:这道题开2000000就好。

      嗯= =其实就是把线段树update和query写两遍233

      蛋碎了一地。数组开大MLE,数组开小RE。

      这道题外层区间内层权值有点麻烦,所以换一种思路:外层权值线段树内层区间线段树。递归查询某一段权值范围内有多少数,若个数小于询问数则向左子树递归,否则向右子树递归。

      = =

      好吧我的确给别人讲不懂 _(:з」∠)_

      代码常熟大地飞起。标记永久化是什么可以吃吗

      yky大爷讲了一种奥妙丛丛的压缩空间的方法:把结构体里的变量压缩为x位整型。因为好像存和要用unsigned int于是干脆用long long。具体用法看代码。

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 struct seg1
      5 {
      6     ll l:28, r:28, sum:36, lazy:36;
      7 }p1[20000005];
      8 struct operation
      9 {
     10     ll op, l, r, val;
     11 }op[50005];
     12 ll n, p2[150005], ptot, cd[50005], ctot, ql, qr, val;
     13   
     14 void push_up(ll o, ll l, ll r)
     15 {
     16     p1[o].sum = p1[p1[o].l].sum + p1[p1[o].r].sum + p1[o].lazy * (r - l + 1);
     17 }
     18   
     19 void push_down(ll o, ll l, ll r)
     20 {
     21     ll mid = (l + r) >> 1;
     22     if(!p1[o].l) p1[o].l = ++ptot;
     23     if(!p1[o].r) p1[o].r = ++ptot;
     24     if(p1[o].lazy)
     25     {
     26         p1[p1[o].l].lazy += p1[o].lazy;
     27         p1[p1[o].r].lazy += p1[o].lazy;
     28         p1[p1[o].l].sum += p1[o].lazy * (mid - l + 1);
     29         p1[p1[o].r].sum += p1[o].lazy * (r - mid);
     30         p1[o].lazy = 0;
     31     }
     32 }
     33   
     34 void update1(ll o, ll l, ll r)
     35 {
     36     ll mid = (l + r) >> 1;
     37     if(ql <= l && r <= qr)
     38     {
     39         p1[o].sum += r - l + 1, p1[o].lazy++;
     40         return;
     41     }
     42     push_down(o, l, r);
     43     if(ql <= mid) update1(p1[o].l, l, mid);
     44     if(mid < qr) update1(p1[o].r, mid + 1, r);
     45     push_up(o, l, r);
     46 }
     47   
     48 void update2(ll o, ll l, ll r)
     49 {
     50     ll mid = (l + r) >> 1;
     51     if(!p2[o]) p2[o] = ++ptot;
     52     update1(p2[o], 1, n);
     53     if(l == r) return;
     54     if(val <= mid) update2(o << 1, l, mid);
     55     else update2(o << 1 | 1, mid + 1, r);
     56 }
     57   
     58 ll query1(ll o, ll l, ll r)
     59 {
     60     ll mid = (l + r) >> 1, cnt = 0;
     61     if(ql <= l && r <= qr) return p1[o].sum;
     62     push_down(o, l, r);
     63     if(ql <= mid) cnt = query1(p1[o].l, l, mid);
     64     if(mid < qr) cnt += query1(p1[o].r, mid + 1, r);
     65     return cnt;
     66 }
     67   
     68 ll query2(ll o, ll l, ll r, ll rk)
     69 {
     70     ll mid = (l + r) >> 1;
     71     if(l == r) return l;
     72     if(!p2[o]) p2[o] = ++ptot;
     73     val = query1(p2[o << 1 | 1], 1, n);
     74     if(val < rk) return query2(o << 1, l, mid, rk - val);
     75     return query2(o << 1 | 1, mid + 1, r, rk);
     76 }
     77   
     78 int main()
     79 {
     80     ll m;
     81     scanf("%lld%lld", &n, &m);
     82     for(ll i = 1; i <= m; i++)
     83     {
     84         scanf("%lld%lld%lld%lld", &op[i].op, &op[i].l, &op[i].r, &op[i].val);
     85         if(op[i].op == 1) cd[++ctot] = op[i].val;
     86     }
     87     sort(cd + 1, cd + ctot + 1);
     88     for(int i = 1; i <= m; i++)
     89         if(op[i].op == 1)
     90             op[i].val = lower_bound(cd + 1, cd + ctot + 1, op[i].val) - cd;
     91     for(ll i = 1; i <= m; i++)
     92         if(op[i].op == 1)
     93         {
     94             ql = op[i].l, qr = op[i].r, val = op[i].val;
     95             update2(1, 1, ctot);
     96         }
     97         else
     98         {
     99             ql = op[i].l, qr = op[i].r;
    100             printf("%lld
    ", cd[query2(1, 1, ctot, op[i].val)]);
    101         }
    102     return 0;
    103 }
    View Code
  • 相关阅读:
    不可或缺 Windows Native (15)
    不可或缺 Windows Native (14)
    不可或缺 Windows Native (13)
    不可或缺 Windows Native (12)
    不可或缺 Windows Native (11)
    不可或缺 Windows Native (10)
    不可或缺 Windows Native (9)
    不可或缺 Windows Native (8)
    不可或缺 Windows Native (7)
    不可或缺 Windows Native (6)
  • 原文地址:https://www.cnblogs.com/CtrlCV/p/5414921.html
Copyright © 2011-2022 走看看