• 牛客暑假多校第一场 J Different Integers


    题意:给你一个数组, q次询问, 每次询问都会有1个[l, r] 求 区间[1,l] 和 [r, n] 中 数字的种类是多少。

    解法1, 莫队暴力:

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
     4 #define LL long long
     5 #define ULL unsigned LL
     6 #define fi first
     7 #define se second
     8 #define pb push_back
     9 #define lson l,m,rt<<1
    10 #define rson m+1,r,rt<<1|1
    11 #define max3(a,b,c) max(a,max(b,c))
    12 #define min3(a,b,c) min(a,min(b,c))
    13 typedef pair<int,int> pll;
    14 const int inf = 0x3f3f3f3f;
    15 const LL INF = 0x3f3f3f3f3f3f3f3f;
    16 const LL mod =  (int)1e9+7;
    17 const int N = 2e5 + 100;
    18 int n, m, blo;
    19 int a[N];
    20 struct Node{
    21     int l, r, id, ans;
    22 }q[N];
    23 bool cmp(Node x1, Node x2){
    24     if(x1.l/blo !=  x2.l / blo) return x1.l < x2.l;
    25     if((x1.l / blo) & 1)    return x1.r < x2.r;
    26     else    return x1.r > x2.r;
    27 }
    28 int cnt[N];
    29 int tot;
    30 int ans[N];
    31 void add(int p){
    32     //cout << p << endl;
    33     cnt[a[p]]++;
    34     if(cnt[a[p]] == 1) tot++;
    35 }
    36 void Remove(int p){
    37     cnt[a[p]]--;
    38     if(cnt[a[p]] == 0) tot--;
    39 }
    40 int main(){
    41     while(~scanf("%d%d", &n, &m)){
    42         memset(cnt, 0, sizeof(cnt));
    43         tot = 0;
    44         blo = 500 + 1;
    45         for(int i = 1; i <= n; i++)
    46             scanf("%d", &a[i]);
    47         for(int i = 1; i <= m; i++){
    48             scanf("%d%d", &q[i].l, &q[i].r);
    49             q[i].id = i;
    50         }
    51         sort(q+1, q+1+m, cmp);
    52         int L = 0, R = n+1;
    53         for(int i = 1; i <= m; i++){
    54             int nl = q[i].l;
    55             int nr = q[i].r;
    56             while(L < nl) add(++L);
    57             while(L > nl) Remove(L--);
    58             while(R > nr) add(--R);
    59             while(R < nr) Remove(R++);
    60             ans[q[i].id] = tot;
    61         }
    62         for(int i = 1; i <= m; i++){
    63             printf("%d
    ", ans[i]);
    64         }
    65     }
    66     return 0;
    67 }
    View Code

    解法2, 离线询问, 按r从小到打排序, 每次r往右边移动的时候, 如果r移除的时候移除了 x 最后一次出现的位置, 那么就在x第一次出现的位置标记一下。 每次询问的时候答案就为[1,l] 标记数字出现的次数 + 右边的值。我们用树状数组来优化[1,l]的和。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
     4 #define LL long long
     5 #define ULL unsigned LL
     6 #define fi first
     7 #define se second
     8 #define pb push_back
     9 #define lson l,m,rt<<1
    10 #define rson m+1,r,rt<<1|1
    11 #define max3(a,b,c) max(a,max(b,c))
    12 #define min3(a,b,c) min(a,min(b,c))
    13 typedef pair<int,int> pll;
    14 const int inf = 0x3f3f3f3f;
    15 const LL INF = 0x3f3f3f3f3f3f3f3f;
    16 const LL mod =  (int)1e9+7;
    17 const int N = 2e5 + 100;
    18 int cnt[N], last[N], first[N];
    19 int a[N], ans[N];
    20 int n, m, tot;
    21 struct Node{
    22     int l, r, id;
    23     bool operator <(Node &x) const{
    24         return r < x.r;
    25     }
    26 }q[N];
    27 void Add(int x){
    28     while(x <= n){
    29         cnt[x]++;
    30         x += x&(-x);
    31     }
    32 }
    33 int Query(int x){
    34     int ret = 0;
    35     while(x){
    36         ret += cnt[x];
    37         x -= x&(-x);
    38     }
    39     return ret;
    40 }
    41 int main(){
    42     while(~scanf("%d%d", &n, &m)){
    43         memset(cnt, 0, sizeof(cnt));
    44         memset(last, 0, sizeof(last));
    45         memset(first, 0, sizeof(first));
    46         tot = 0;
    47         for(int i = 1; i <= n; i++){
    48             scanf("%d", &a[i]);
    49             if(first[a[i]] == 0){
    50                 first[a[i]] = i;
    51                 tot++;
    52             }
    53             last[a[i]] = i;
    54         }
    55         for(int i = 1; i <= m; i++){
    56             scanf("%d%d", &q[i].l, &q[i].r);
    57             q[i].id = i;
    58         }
    59         sort(q+1, q+1+m);
    60         int R = 1;
    61         for(int i = 1; i <= n; i++){
    62             while(R < q[i].r){
    63                 if(last[a[R]] == R){
    64                     Add(first[a[R]]);
    65                     tot--;
    66                 }
    67                 R++;
    68             }
    69             ans[q[i].id] = tot + Query(q[i].l);
    70         }
    71         for(int i = 1; i <= m; i++)
    72             printf("%d
    ", ans[i]);
    73     }
    74     return 0;
    75 }
    View Code

    还有蔡队的写法, 直接复制一份原来的数组在后面, 将2个区间的问题转化成一个区间求数字的问题,然后就可以套主席树的板子了。

  • 相关阅读:
    面向对象的三个基本特征(讲解)
    GridView 72般绝技
    Asp.net 将数据库里的记录转换成json
    jquery json asp.net 将各种对象:list ..等转换成
    sql2000 分页存储过程
    .NET中DataSet转化Json工具类
    从攻击者痕迹看内网常见命令
    从攻击者角度看SetMpreference小结
    Java NIO 实现服务端和客户端的通信示例
    spark streaming 监听器执行顺序
  • 原文地址:https://www.cnblogs.com/MingSD/p/9341222.html
Copyright © 2020-2023  润新知