【bzoj2453&2120】维护队列(数颜色)

2015.04.27 20:25 Mon | 21次阅读 | 旧日oi | 固定链接 | 源码

Description

你小时候玩过弹珠吗?
小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N。为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少。当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色。但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助。

Input

输入文件第一行包含两个整数N和M。
第二行N个整数,表示初始队列中弹珠的颜色。
接下来M行,每行的形式为“Q L R”或“R x c”,“Q L R”表示A想知道从队列第L个弹珠到第R个弹珠中,一共有多少不同颜色的弹珠,“R x c”表示A把x位置上的弹珠换成了c颜色。

Output

对于每个Q操作,输出一行表示询问结果。

Sample Input

2 3
1 2
Q 1 2
R 1 2
Q 1 2

Sample Output

2
1

HINT

对于100%的数据,有1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。

题解

分块第二题,跟上一个差不多,都很裸。
感觉做分块的题,别想太优的算法,时间复杂度能承受的范围下能暴力就暴力吧,10^7加大常数都不要管。

我的程序

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<bitset>
#include<stack>
#include<ctime>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define maxn 1000010
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,q,block,x,y;
int pos[maxn],pre[maxn],a[maxn],b[maxn],c[maxn];
char s[2];
void reset(int x)
{
    int l=(x-1)*block+1,r=min(n,x*block);
    for(int i=l;i<=r;i++) b[i]=pre[i];
    sort(b+l,b+r+1);
}
void update(int x,int y)
{
    for(int i=1;i<=n;i++) c[a[i]]=0;
    a[x]=y;
    for(int i=1;i<=n;i++)
    {
        int tmp=pre[i];
        pre[i]=c[a[i]];
        if(pre[i]!=tmp) reset(pos[i]);
        c[a[i]]=i;
    }
}
int find(int x,int v)
{
    return lower_bound(b+(x-1)*block+1,b+x*block+1,v)-(b+(x-1)*block)-1;
}
int query(int l,int r)
{
    int sum=0;
    if(pos[l]==pos[r])
    {
        for(int i=l;i<=r;i++) if(pre[i]<l) sum++;
        return sum;
    }
    for(int i=l;i<=pos[l]*block;i++) if(pre[i]<l) sum++;
    for(int i=(pos[r]-1)*block+1;i<=r;i++) if(pre[i]<l) sum++;
    for(int i=pos[l]+1;i<pos[r];i++) sum+=find(i,l);
    return sum;
}
int main()
{
    cin>>n>>q;block=int(sqrt(n));
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        pos[i]=(i-1)/block+1;
        pre[i]=c[a[i]];
        c[a[i]]=i;
    };
    if(n%block) m=n/block+1;
    else m=n/block;
    for(int i=1;i<=m;i++) reset(i);
    while(q--)
    {
        scanf("%s%d%d",s,&x,&y);
        if(s[0]=='R') update(x,y);
        else printf("%d\n",query(x,y));
    }
}```