0
点赞
收藏
分享

微信扫一扫

分块模板


//有n个数,两种操作:M L R W:对[L,R]内元素都加上W;A L R C:求[L,R]内元素大于等于C的个数
const int N = 1e6 + 10;

int n, m;
int block, sz;
int pos[N], L[N], R[N], add[N];//add数组相当于lazy标记
int a[N], b[N];
void reset(int x)
{
    for(int i = L[x]; i <= R[x]; i++) b[i] = a[i];
    sort(b + L[x], b + R[x] + 1);
}
void init()
{
    block = (int)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;
    for(int i = 1; i <= sz; i++) reset(i);
}
void update(int l, int r, int c)
{
    int lb = pos[l], rb = pos[r];
    if(lb == rb)
    {
        for(int i = l; i <= r; i++) a[i] += c;
        reset(lb);
    }
    else
    {
        for(int i = l; i <= R[lb]; i++) a[i] += c;
        for(int i = L[rb]; i <= r; i++) a[i] += c;
        for(int i = lb + 1; i < rb; i++) add[i] += c;
        reset(lb);
        reset(rb);
    }
}
int bin_serach(int x, int c)
{//二分查询块内大于等于c的数量
    int l = L[x], r = R[x];
    int ans = R[x] + 1;//初始设为超尾
    while(l <= r)
    {
        int mid = (l + r) / 2;
        if(b[mid] >= c) r = mid - 1, ans = mid;
        else l = mid + 1;
    }
    return R[x] - ans + 1;
}
int query(int l, int r, int c)
{
    int lb = pos[l], rb = pos[r];
    int ans = 0;
    if(lb == rb)
    {
        for(int i = l; i <= r; i++)
            if(a[i] + add[lb] >= c) ans++;
    }
    else
    {
        for(int i = l; i <= R[lb]; i++)
            if(a[i] + add[lb] >= c) ans++;
        for(int i = L[rb]; i <= r; i++)
            if(a[i] + add[rb] >= c) ans++;
        for(int i = lb + 1; i < rb; i++)
            ans += bin_serach(i, c - add[i]);
    }
    return ans;
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    init();
    char ch;
    int a, b, c;
    for(int i = 1; i <= m; i++)
    {
        scanf(" %c%d%d%d", &ch, &a, &b, &c);
        if(ch == 'M') update(a, b, c);
        else printf("%d\n", query(a, b, c));
    }
    return 0;
}

//给出一个有n个元素的数组,有以下两种操作:Q x y,求出区间[x,y)内不同元素的个数,M x y,把第x个元素的值修改为y。题目中的下标是从0开始的
#include <bits/stdc++.h>
using namespace std;

const int N = 50000 + 10, M = 1000000 + 10, INF = 0x3f3f3f3f;

int n, m;
int block, sz;
int pos[N], L[N], R[N], pre[N];
int last[M];
int a[N], b[N];
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 init()
{
    block = 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)
{
    if(a[x] == v) return;
    int idx = -1, idv = -1;
    for(int i = x+1; i <= n; i++)
    {
        if(a[i] == a[x] && idx == -1) idx = i;
        else if(a[i] == v && idv == -1) idv = i;

        if(idx != -1 && idv != -1) break;
    }
    if(idv != -1) b[idv] = x, reset(pos[idv]);
    idv = x;
    for(int i = x-1; i >= 1; i--)
    {
        if(a[i] == a[x] && idx != -1) b[idx] = i, reset(pos[idx]), idx = -1;
        if(a[i] == v && idv != -1) b[idv] = i, reset(pos[idv]), idv = -1;
        if(idx == -1 && idv == -1) break;
    }
    if(idx != -1) b[idx] = 0, reset(pos[idx]);
    if(idv != -1) b[idv] = 0, reset(pos[idv]);
    a[x] = v;
}
int query(int l, int r)
{
    int lb = pos[l], rb = pos[r];
    int ans = 0;
    if(lb == rb)
    {
        for(int i = l; i <= r; i++)
            if(b[i] < l) ans++;
    }
    else
    {
        for(int i = l; i <= R[lb]; i++)
            if(b[i] < l) ans++;
        for(int i = L[rb]; i <= r; i++)
            if(b[i] < l) ans++;
        for(int i = lb + 1; i < rb; i++)
            ans += lower_bound(pre + L[i], pre + R[i] + 1, l) - (pre + L[i]);
    }
    return ans;
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    init();
    char ch;
    int x, y;
    for(int i = 1; i <= m; i++)
    {
        scanf(" %c%d%d", &ch, &x, &y);
        if(ch == 'Q') printf("%d\n", query(x+1, y));
        else update(x+1, y);
    }
    return 0;
}


举报

相关推荐

0 条评论