[模板]分块/可修改莫队 (数颜色种类)

模板题地址

题目描述

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令:

1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。

2、 R P Col 把第P支画笔替换为颜色Col。

为了满足墨墨的要求,你知道你需要干什么了吗?

范围N,M <=10000   每个数都<=10^6

刚学会莫队就说说莫队:一种离线处理询问区间的好办法,虽然看上去超级暴力,但是很快。

把询问按左右端点排序,每次移动两个端点在O(1)的时间内更新答案即可。

while(L<q[i].l){/*O(1)更新答案*/L++;}
while(L>q[i].l){L--;/*O(1)更新答案*/}
while(R<q[i].r){R++;/*O(1)更新答案*/}
while(R>q[i].r){/*O(1)更新答案*/R--;}

当然还要用到分块的优化。

P.S.排序以左端点所在的块为第一关键字,右端点为第二关键字

struct Node{
    int l,r,id;
    bool operator <(const Node a){
        if(belong[l]==belong[a.l])return r<a.r;
        else return belong[l]<belong[a.l];
    }
}q[MAXN];

感觉是不是暴力得让人难以接受=、=  , 就是好用!

然而话说回来这个题带上了修改。

之前没有修改我们排序的是一个(l,r)

带了修改就不妨加上一维时间轴,排序这个(l,r,t)

再按照朴素的方法做,问题就迎刃而解了。

代码

#include<bits/stdc++.h>
#define MAXN 10010
using namespace std;
int N,M,Q,siz,tim,a[MAXN],belong[MAXN],ans[MAXN],color[100010],tmp;
struct Node{
    int l,r,id,t;
    bool operator <(const Node a){
        if(belong[l]==belong[a.l]){
            if(r==a.r)return t<a.t;
            else return r<a.r;
        }
        else return belong[l]<belong[a.l];
    }
}q[MAXN];
struct change{
    int x,y;
}c[MAXN];
void Change(int now,int i){
    if(c[now].x>=q[i].l&&c[now].x<=q[i].r){
        color[a[c[now].x]]--;
        if(color[a[c[now].x]]==0)tmp--;
        if(color[c[now].y]==0)tmp++;
        color[c[now].y]++;
    }
    swap(a[c[now].x],c[now].y);
}
int main()
{
    scanf("%d%d",&N,&M);
    siz=sqrt(N);
    for(int i=1;i<=N;i++)scanf("%d",&a[i]),belong[i]=(i-1)/siz+1;
    for(int i=1;i<=M;i++){
        int a,b;char s[5];
        scanf("%s%d%d",s,&a,&b);
        if(s[0]=='Q')
                q[++Q]=(Node){a,b,Q,tim};
        else     c[++tim]=(change){a,b}; 
    }
    sort(q+1,q+Q+1);
    int L=0,R=0,now=0;
    for(int i=1;i<=Q;i++){
        while(L<q[i].l){color[a[L]]--;if(color[a[L]]==0)tmp--;L++;}
        while(L>q[i].l){L--;color[a[L]]++;if(color[a[L]]==1)tmp++;}
        while(R<q[i].r){R++;color[a[R]]++;if(color[a[R]]==1)tmp++;}
        while(R>q[i].r){color[a[R]]--;if(color[a[R]]==0)tmp--;R--;}
        while(now<q[i].t){now++;Change(now,i);}
        while(now>q[i].t){Change(now,i);now--;}
        ans[q[i].id]=tmp;
    }
    for(int i=1;i<=Q;i++)
        printf("%d
",ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/Elfish/p/7697851.html