• [AHOI2013]作业 & Gty的二逼妹子序列 莫队


    ~~~题面~~~

    题解:

      题目要求统计一个区间内数值在[a, b]内的数的个数和种数,而这个是可以用树状数组统计出来的,所以可以考虑莫队。

      考虑区间[l, r]转移到[l, r + 1],那么对于维护个数的树状数组就直接加即可。

      对于维护种数的树状数组,我们额外维护一个数组num,表示数a在区间内出现了多少次,如果是新出现的,那么就加入树状数组。
      如果要删除一个数并且这个数在区间内只出现了一次,那么就删除这个数。注意不论什么情况都要实时维护num数组。

      然后莫队即可。

      Gty的二逼妹子序列是洛谷P4867和作业的某一问是一模一样的,把数组开大点就可以过。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define R register int
      4 #define AC 100100
      5 
      6 int n, m, cnt, block;
      7 int ans1[AC], ans2[AC], s[AC], num[AC], tot[AC];
      8 
      9 struct node{
     10     int l, r, a, b, id;
     11 }q[AC];
     12 
     13 inline int lowbit(int x)
     14 {
     15     return x & (-x);
     16 }
     17 
     18 struct kkk{
     19     int a[AC];
     20     
     21     void add(int x, int y)
     22     {
     23         for(R i = x; i <= cnt; i += lowbit(i)) a[i] += y;
     24     }
     25     
     26     int find(int x)
     27     {
     28         int rnt = 0;
     29         for(R i = x; i; i -= lowbit(i)) rnt += a[i];
     30         return rnt;
     31     }
     32 }c1, c2;
     33 
     34 inline int read()
     35 {
     36     int x = 0;char c = getchar();
     37     while(c > '9' || c < '0') c = getchar();
     38     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
     39     return x;
     40 }
     41 
     42 int half(int x)//查询离散化后的值
     43 {
     44     int l = 1, r = cnt, mid;
     45     while(l < r)
     46     {
     47         mid = (l + r) >> 1;
     48         if(num[mid] == x) return mid;
     49         else if(num[mid] > x) r = mid;
     50         else l = mid + 1;
     51     }
     52     return l;
     53 }
     54 
     55 int half1(int x)//查询最小的大于等于a的值
     56 {
     57     int l = 1, r = cnt, mid;
     58     if(num[cnt] < x) return cnt + 1;
     59     while(l < r)
     60     {
     61         mid = (l + r) >> 1;
     62         if(num[mid] >= x) r = mid;
     63         else l = mid + 1;
     64     }
     65     return l;
     66 }
     67 
     68 int half2(int x)//查询最大的小于等于b的值
     69 {
     70     int l = 1, r = cnt, mid;
     71     if(num[1] > x) return 0;
     72     while(l < r)
     73     {
     74         mid = (l + r + 1) >> 1;//强制偏右
     75         if(num[mid] > x) r = mid - 1;
     76         else l = mid; 
     77     }
     78     return l;
     79 }
     80 
     81 inline bool cmp(node a, node b)
     82 {
     83     if(a.l / block != b.l / block) return a.l < b.l;
     84     else return a.r < b.r;//分块排序
     85 }
     86 
     87 void pre()
     88 {
     89     n = read(), m = read(), block = sqrt(n);
     90     for(R i = 1; i <= n; i ++) s[i] = num[i] = read();
     91     sort(num + 1, num + n + 1);
     92     for(R i = 1; i <= n; i ++) 
     93         if(num[i] != num[i + 1]) num[++cnt] = num[i];
     94     for(R i = 1; i <= n; i ++) s[i] = half(s[i]);//在这里离散化,这样后面就不用调用了
     95     for(R i = 1; i <= m; i ++)
     96     {
     97         q[i].l = read(), q[i].r = read(), q[i].id = i;
     98         q[i].a = half1(read()), q[i].b = half2(read());
     99     }
    100     sort(q + 1, q + m + 1, cmp);
    101 }
    102 
    103 void add(int x)
    104 {
    105     c1.add(x, 1);
    106     if(!tot[x]) c2.add(x, 1);
    107     ++ tot[x];
    108 }
    109 
    110 void del(int x)
    111 {
    112     c1.add(x, -1);
    113     -- tot[x];
    114     if(!tot[x]) c2.add(x, -1);
    115 }
    116 
    117 void work()//这里每个点的贡献与区间无关,相对独立,所以不用考虑顺序问题
    118 {
    119     int l, r;
    120     for(R i = q[1].l; i <= q[1].r; i ++) add(s[i]);
    121     ans1[q[1].id] = c1.find(q[1].b) - c1.find(q[1].a - 1);
    122     ans2[q[1].id] = c2.find(q[1].b) - c2.find(q[1].a - 1);
    123     l = q[1].l, r = q[1].r;
    124     for(R i = 2; i <= m; i ++)
    125     {
    126         int ll = q[i].l, rr = q[i].r;
    127         while(ll < l) -- l, add(s[l]);
    128         while(ll > l) del(s[l]), ++ l;
    129         while(rr > r) ++ r, add(s[r]);
    130         while(rr < r) del(s[r]), -- r;
    131         ans1[q[i].id] = c1.find(q[i].b) - c1.find(q[i].a - 1);
    132         ans2[q[i].id] = c2.find(q[i].b) - c2.find(q[i].a - 1);
    133     }
    134     for(R i = 1; i <= m; i ++) printf("%d %d
    ", ans1[i], ans2[i]);
    135 }
    136 
    137 int main()
    138 {
    139 //    freopen("in.in", "r", stdin);
    140     pre();
    141     work();
    142 //    fclose(stdin);
    143     return 0;
    144 }
    View Code
  • 相关阅读:
    Python的Crypto模块使用:自动输入Shell中的密码
    算法之动态规划初步(Java版)
    基于ZXing的二维码,你可以这样改造它
    Java字符编码的转化问题
    第一个Hadoop程序——WordCount
    Hadoop的学习前奏(二)——Hadoop集群的配置
    Linux下的一些问题收集及解决方法(二)
    Python的捕虫笔记
    Hadoop的学习前奏(一)——在Linux上安装与配置Hadoop
    Android SnackBar:你值得拥有的信息提示控件
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9614399.html
Copyright © 2020-2023  润新知