bzoj 2120: 数颜色

莫队水过

每次修改之间的询问用莫队搞一下,还挺快……

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
#define MAXN 100003
#define MAXQ 100003
int n, a[MAXN], sqrtn;
struct Qtype
{
    int num;
    char opt;
    int x, y;
} qy[MAXQ];
bool cmp(const Qtype &a, const Qtype &b)
{
    int ax = a.x / sqrtn, bx = b.x / sqrtn;
    if (ax != bx)
        return ax < bx;
    return a.y < b.y;
}
map<int, int> lisan;
int lct = 0;
int ct[MAXN], ans[MAXN];
void work(int ql, int qr)
{
    int l, r, m;
    l = r = m = 0;
    memset(ct, 0, sizeof(ct));
    for (int i = ql; i < qr; ++i)
        qy[i].num = i - ql;
    sort(qy + ql, qy + qr, cmp);
    for (int i = ql; i < qr; ++i)
    {
        while (l < qy[i].x)
        {
            if (--ct[a[l]] == 0)
                --m;
            ++l;
        }
        while (l > qy[i].x)
        {
            --l;
            if (++ct[a[l]] == 1)
                ++m;
        }
        while (r < qy[i].y)
        {
            if (++ct[a[r]] == 1)
                ++m;
            ++r;
        }
        while (r > qy[i].y)
        {
            --r;
            if (--ct[a[r]] == 0)
                --m;
        }
        ans[qy[i].num] = m;
    }
    for (int i = ql; i < qr; ++i)
        printf("%d\n", ans[i - ql]);
}
int main()
{
    int Q;
    scanf("%d%d", &n, &Q);
    sqrtn = sqrt(n);
    for (int i = 0; i < n; ++i)
        scanf("%d", &a[i]);
    for (int i = 0; i < Q; ++i)
    {
        scanf(" %c%d%d", &qy[i].opt, &qy[i].x, &qy[i].y);
        --qy[i].x;
    }
    for (int i = 0; i < n; ++i)
    {
        map<int, int>::iterator it = lisan.find(a[i]);
        if (it == lisan.end())
        {
            lisan[a[i]] = lct;
            a[i] = lct++;
        }
        else
            a[i] = it->second;
    }
    for (int i = 0; i < Q; ++i)
        if (qy[i].opt == 'R')
        {
            map<int, int>::iterator it = lisan.find(qy[i].y);
            if (it == lisan.end())
            {
                lisan[qy[i].y] = lct;
                qy[i].y = lct++;
            }
            else
                qy[i].y = it->second;
        }
    int last = 0;
    for (int i = 0; i <= Q; ++i)
        if (i == Q)
            work(last, i);
        else if (qy[i].opt == 'R')
        {
            work(last, i);
            a[qy[i].x] = qy[i].y;
            last = i + 1;
        }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值