• bzoj 2120 数颜色 (带修莫队)


    题目链接:

    https://www.lydsy.com/JudgeOnline/problem.php?id=2120

    题意:两种操作:Q 询问区间  l - r  内颜色的种类 ,R 单点修改

    思路:

    带修莫队与普通莫队不同之处就是,带修莫队可以支持修改操作,我们可以再维护一维来表示操作的时间,那么离线处理询问时,我们就需要维护 l,r,t,三根指针,同时因为是三根指针

    块的大小分成 n的2/3次方,其他地方和普通莫队维护是一样的,只是多维护了一维操作时间,可能看上去会绕一点。

    实现代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 1e4 + 10;
    
    struct node{
        int l,r,t,id;
        node(int l=0,int r=0,int t=0,int id=0):l(l),r(r),t(t),id(id){}
    }q[M];
    
    struct node1{
        int pos,now,old;
        node1(int pos=0,int now=0,int old=0):pos(pos),now(now),old(old){}
    }c[M];
    
    int n,m,block,l,r,num[M],a[M],now[M],flag[M*100],ans;
    //排序优先度如果l,r都在一个块中,那么优先选择t小的
    bool cmp(node a,node b){
       if(a.l/block != b.l/block){
          if(a.r/block != b.r/block){
              return a.t < b.t;
          }
          return a.r < b.r;
       }
       return a.l < b.l;
    }
    
    void add(int col,int val){
        flag[col] += val;
        if(val > 0) ans += (flag[col] == 1);
        else if(val < 0) ans -= (flag[col]==0);
    }
    
    void solve(int pos,int col){
        if(pos >= l&&pos <= r) add(col,1),add(a[pos],-1);
        a[pos] = col;
    }
    
    int main()
    {
            scanf("%d%d",&n,&m);
            block = (int)pow(n,2.0/3.0);
            for(int i = 1;i <= n;i ++){
                scanf("%d",&a[i]);
                now[i] = a[i];  //now[i] i点现在的颜色
            }
            int k = 0;
            int cnt = 0; ans = 0;
            for(int i = 0;i < m;i ++){
                char op[2];
                int x,y;
                scanf("%s%d%d",&op,&x,&y);
                if(op[0] == 'Q'){
                    //将询问的区间左右节点,在第k次修改之后,第cnt个询问等信息存到结构体q中
                    q[++cnt] = node(x,y,k,cnt);
                }
                else {
                    //将第k次修改的点的左边,要修改的颜色,这个点之前的颜色,存到结构体里
                    c[++k] = node1(x,y,now[x]);
                    now[x] = y;  //x点现在的颜色变为y
                }
            }
            sort(q+1,q+cnt+1,cmp);
            l = 1; r = 0;
            int tim = 0;
            for(int i = 1;i <= cnt;i ++){
                while(tim < q[i].t) solve(c[tim+1].pos,c[tim+1].now),tim++;
                while(tim > q[i].t) solve(c[tim].pos,c[tim].old),tim--;
                while(q[i].l < l) add(a[l-1],1),l--;
                while(q[i].l > l) add(a[l],-1),l++;
                while(q[i].r < r) add(a[r],-1),r--;
                while(q[i].r > r) add(a[r+1],1),r++;
                num[q[i].id] = ans;
            }
            for(int i = 1;i <= cnt;i ++)
                printf("%d
    ",num[i]);
        return 0;
    }

     

     

  • 相关阅读:
    如何用RadioButton做一个底部的切换栏
    自定义有监听器的ScrollView
    ViewPager的使用小技巧
    什么时候用Application的Context,什么时候用Activity的Context
    让改变输入法回车键的图标
    墙内下载DropBox离线安装包的方法
    巧用用layer-list做一个卡片背景
    LeakCanary中英文文档+使用例子
    让你的APK瘦成一道闪电
    用一张图片实现按钮按下和普通效果的样式
  • 原文地址:https://www.cnblogs.com/kls123/p/9426922.html
Copyright © 2020-2023  润新知