BZOJ2120-数颜色(带修改莫队)

2120: 数颜色
Time Limit: 6 Sec Memory Limit: 259 MB
Submit: 7556 Solved: 3071
[Submit][Status][Discuss]
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
题目:BZOJ2120
思路:莫队算法,带修改。
对于带修改莫队的实现:
1.在普通莫队的基础上,增加第三关键字为更新时间,即询问最近一次更新之后
2.增加更新函数和更新记录指针,对于每次询问,如果更新小于当前询问,先暴力更新,并维护答案,然后是普通更新的过程
AC代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define met(s,k) memset(s,k,sizeof s)
#define scan(a) scanf("%d",&a)
#define scanl(a) scanf("%lld",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannl(a,b) scanf("%lld%lld",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define prin(a) printf("%d\n",a)
#define prinl(a) printf("%lld\n",a)
using namespace std;
typedef long long ll;
const  int maxn=2e6+10;
int n,m,unit,ans,ans1[maxn],cont;
int currenl,currenr,time;
struct que
{
    int l,r,pos,cont/*第三关键字,更新戳*/;
}q[maxn];
struct upd
{
    int pos,inter;
}up[maxn];
bool cmp(que a,que b)
{
    int x=a.l/unit;
    int y=b.l/unit;
    if(x!=y)return x<y;
    else if(a.r!=b.r) return a.r<b.r;
    else return a.cont<b.cont;
}
int a[maxn],vis[maxn];
void removeposx(int pos)
{
    if(--vis[a[pos]]==0)ans--;
}
void addposx(int pos)
{
    if(++vis[a[pos]]==1)ans++;
}
void update(int time)//更新函数
{
    if(up[time].pos>=currenl&&up[time].pos<=currenr)//只有更新位置在当前区间内,才会对答案有影响
    {
        if(++vis[up[time].inter]==1)ans++;
        if(--vis[a[up[time].pos]]==0)ans--;
    }
    swap(a[up[time].pos],up[time].inter);//每次更新过后,如果我们要把它更新回来的话,就要把它改到更新之前的值,这个值不一定是最初的数组,所以我们要记下更新之前的值,这里直接交换一下就可以了
}
void modui(int m)
{
    for (int i = 0; i <m; ++i)
    {
        while (currenr<q[i].r)addposx(++currenr);
        while (currenr>q[i].r)removeposx(currenr--);
        while (currenl<q[i].l)removeposx(currenl++);
        while (currenl>q[i].l)addposx(--currenl);
        while (time<q[i].cont)update(++time);//更新可以放在前面,也可以在后面
        while (time>q[i].cont)update(time--);
        ans1[q[i].pos]=ans;
    }
}
int main()
{
    scann(n,m);
    int quest=0;
    currenl=1,currenr=0,time=0/*更新时间戳*/;
    met(vis,0);
    unit=(int)sqrt((double)n);
    for(int i=1;i<=n;i++)scan(a[i]);
    for(int i=0;i< m;i++)
    {
        char c;
        int x,y;
        scanf(" %c%d%d",&c,&x,&y);
        if(c=='Q')
        {
            q[quest].l=x;
            q[quest].r=y;
            q[quest].pos = quest;
            q[quest++].cont=cont;
        }
        if(c=='R')
        {
            up[++cont].pos=x;
            up[cont].inter=y;
        }
    }
    sort(q,q+quest,cmp);
    modui(quest);
    for (int j = 0; j <quest; ++j)prin(ans1[j]);
    return  0;
}

猜你喜欢

转载自blog.csdn.net/swust5120160705/article/details/79582444