BZOJ - 2120 - 数颜色(带修莫队or分块)

2120: 数颜色

Time Limit: 6 Sec  Memory Limit: 259 MB
Submit: 8602  Solved: 3557

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

HINT

对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

带修莫队:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
int n, m, Q, a[MAXN];
struct Query{int id, l, r, Time, ans;} q[MAXN];
struct Change{int pos, Old, New;} c[MAXN];
int block, l, r, T, ans, cnt[MAXN*100], pos[MAXN], now[MAXN];
bool cmp(Query a, Query b)
{
    return pos[a.l]==pos[b.l]?(pos[a.r]==pos[b.r]?a.Time<b.Time:a.r<b.r):a.l<b.l;
}
bool cmp_id(Query A, Query B){ return A.id < B.id; }
void update(int x, int d)
{
    cnt[x] += d;
    if (cnt[x] == 0 && d == -1) ans--;
    if (cnt[x] == 1 && d == 1) ans++;
}
void change(int x, int d)
{
    if (l <= x && x <= r)
    {
        update(d, 1),
        update(a[x], -1);
    }
    a[x] = d;
}
int main()
{
    scanf("%d%d", &n, &m);
    block = pow(n, 2.0/3);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        now[i] = a[i];
        pos[i] = (i-1)/block+1;
    }

    while (m--)
    {
        char op; int x, y; scanf(" %c %d%d", &op, &x, &y);
        if (op == 'Q') q[Q++] = Query{Q, x, y, T};
        if (op == 'R') c[++T] = Change{x, now[x], y}, now[x] = y;
    }
    sort(q, q+Q, cmp);
    l = 1, r = 0, T = 0, ans = 0;
    for (int i = 0; i < Q; i++)
    {
        //由于函数参数的执行顺序的问题++和--的位置和顺序一定不能错
        while (T < q[i].Time) change(c[T].pos, c[++T].New);//T先++,然后传给两个参数
        while (T > q[i].Time) change(c[T--].pos, c[T].Old);//先传给两个参数然后T--
        while (l < q[i].l) update(a[l++], -1);
        while (l > q[i].l) update(a[--l],  1);
        while (r < q[i].r) update(a[++r],  1);
        while (r > q[i].r) update(a[r--], -1);
        q[i].ans = ans;
    }
    sort(q, q+Q, cmp_id);
    for (int i = 0; i < Q; i++) printf("%d\n", q[i].ans);
    return 0;
}
/*
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
*/

分块:

#include <bits/stdc++.h>
using namespace std;
const int N = 5e4+10, M = 1e6+10, INF = 0x3f3f3f3f;
inline int read()
{
    char ch = getchar(); int x = 0, f = 1;
    while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    while('0' <= ch && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
int n, m, block, sz, pos[N], L[N], R[N], pre[N], last[M], a[N], b[N];
char ch[10];
void reset(int x)
{
    for(int i = L[x]; i <= R[x]; i++) pre[i] = b[i];
    sort(pre + L[x], pre + R[x] + 1);
}
void build()
{
    block = 0.5 * sqrt(n);
    sz = n / block;
    if(n % block) sz++;
    for(int i = 1; i <= n; i++) pos[i] = (i-1) / block + 1;
    for(int i = 1; i <= sz; i++)
    {
        L[i] = (i-1) * block + 1;
        R[i] = i * block;
    }
    R[sz] = n;
    memset(last, 0, sizeof last);
    for(int i = 1; i <= n; i++)
    {
        b[i] = last[a[i]];
        last[a[i]] = i;
    }
    for(int i = 1; i <= sz; i++) reset(i);
}
void update(int x, int v) //直接更新所有点的前驱节点
{
   for(int i = 1; i <= n; i++) last[a[i]] = 0;
   a[x] = v;
   for(int i = 1; i <= n; i++)
   {
       int tmp = b[i];
       b[i] = last[a[i]];
       if(tmp != b[i]) reset(pos[i]);
       last[a[i]] = i;
   }
}
int query(int x, int y)
{
    int t1 = pos[x], t2 = pos[y];
    int ans = 0;
    for(int i = x; i <= min(R[t1], y); i++)
        if(b[i] < x) ans++;
    if(t1 != t2) for(int i = L[t2]; i <= y; i++)
            if(b[i] < x) ans++;
        for(int i = t1 + 1; i < t2; i++)
            ans += lower_bound(pre + L[i], pre + R[i] + 1, x) - (pre + L[i]);
    return ans;
}
int main()
{
    n = read(); m = read();
    for(int i = 1; i <= n; i++) a[i] = read();
    build();
    int x, y;
    for(int i = 1; i <= m; i++)
    {
        scanf("%s",&ch); x = read(); y = read();
        if(ch[0] == 'Q') printf("%d\n", query(x, y));
        else update(x, y);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sugarbliss/article/details/81216089