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\n",num[i]);
    return 0;
}

 

 

 

posted @ 2018-08-05 19:55  冥想选手  阅读(127)  评论(0编辑  收藏  举报