• [带修莫队] Bzoj 2120 数颜色


    Description

    墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

    Input

    第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

    Output

    对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

    Sample Input

    6 5
    1 2 3 4 5 5
    Q 1 4
    Q 2 6
    R 1 2
    Q 1 4
    Q 2 6

    Sample Output

    4
    4
    3
    4

    HINT

    对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

    题解

    • 可修改的莫队,怎么做呢?

    • 普通的莫队做法肯定会爆炸

    • 我们可以先引入一个“修改时间”,表示当前询问是发生在前Time个修改后的。

    • 也就是说我们在做莫队的时候除了原先的两个l,r指针,还引入时间指针,可以通过时间倒流或时光推移来保证正确性

    • 按照原先的sort函数来说,使得每个询问最坏情况下时间指针可以移动n次,总共就n^2次,极其不优秀,那么下面我们就要用三关键字排序来做

    • 时间复杂度分析:(num=sqrt(n))

    • ①对于l指针,依旧是O(num*n)

    • ②对于r指针,也依旧是O(n*n/num)

    • ③对于t指针(时间指针):

    • 我们要寻找有多少个单调段(一个单调段下来最多移动n次) 在排序函数里,当且仅当两个询问l在同块,r也在同块时,才会对可怜的t进行排序。

    • 对于每一个l的块,里面r最坏情况下占据了所有的块

    • 所以最坏情况下:有n/num个l的块,每个l的块中会有n/num个r的块,此时,在一个r块里,就会出现有序的t。

    • 所以t的单调段个数为:(n/unit)^2。

    • 每个单调段最多移动n次。 最后所以时间指针的时间复杂度为 O((n/num)^2*n)

    • 三个指针汇总:O(num*n+n^2/num+(n/num)^2*n)。当num=2/3n时,时间最优秀,为O(n^3/5)

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cmath>
     5 #define N 10010
     6 using namespace std;
     7 struct Query{int l,r,t,d;}q[N];
     8 struct Change{int w,l,r;}p[N];
     9 int n,m,ans,l=1,r,k,a[N],col[N*100],Time,numq,now[N],num,bel[N],Ans[N];
    10 bool cmp(Query a,Query b) { return bel[a.l]==bel[b.l]?(bel[a.r]==bel[b.r]?a.t<b.t:a.r<b.r):a.l<b.l; }
    11 void change(int x,int y) { col[x]+=y; if (y>0) ans+=col[x]==1; if (y<0) ans-=col[x]==0; }
    12 void pd(int x,int y) { if (l<=x&&x<=r) change(y,1),change(a[x],-1); a[x]=y; }
    13 int main()
    14 {
    15     scanf("%d%d",&n,&m),num=pow(n,0.66666);
    16     for (int i=1;i<=n;i++) scanf("%d",&a[i]),now[i]=a[i],bel[i]=i/num+1;
    17     for (int i=1,x,y;i<=m;i++)
    18     {
    19         char ch;
    20         scanf(" %c %d%d",&ch,&x,&y);
    21         if (ch=='Q') q[++numq]=(Query){x,y,Time,numq};
    22         if (ch=='R') p[++Time]=(Change){x,y,now[x]},now[x]=y;
    23     }
    24     sort(q+1,q+numq+1,cmp);
    25     for (int i=1;i<=numq;i++) 
    26     {
    27         while (k<q[i].t) pd(p[k+1].w,p[k+1].l),k++;
    28         while (k>q[i].t) pd(p[k].w,p[k].r),k--;
    29         while (l<q[i].l) change(a[l],-1),l++;
    30         while (l>q[i].l) change(a[l-1],1),l--;
    31         while (r<q[i].r) change(a[r+1],1),r++;
    32         while (r>q[i].r) change(a[r],-1),r--;
    33         Ans[q[i].d]=ans;
    34     }
    35     for (int i=1;i<=numq;i++) printf("%d
    ",Ans[i]);
    36 }
  • 相关阅读:
    Laravel中Contracts的理解和使用
    laravel 服务容器的用法
    linux 安装go环境
    权限设计-系统登录用户权限设计
    Laravel 中使用 JWT 认证的 Restful API
    使用laravel-wechat微信支付
    composer查看全局配置
    如何在 Laravel 项目中处理 Excel 文件
    laravel各种请求类
    Centos创建用户并授权
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10364519.html
Copyright © 2020-2023  润新知