UVA12345 (带修改的莫队)

UVA12345 Dynamic len

Problem :
给一个序列,每次询问一个区间里面的数字种类数量,或者修改某一个位置的值。
Solution :
第一关键字分块排序左端点,第二关键字分块排序右端点,第三关键字排序询问顺序。

左端点移动总的时间复杂度为 q * block_size + block_num * block_size
右端点移动总的时间复杂度为 q * block_size + block_num * block_num * block_size
询问端点总的时间复杂度为 block_num * block_num * n
故取block_size = n^(2/3)

#include <bits/stdc++.h>
using namespace std;

const int N = 50008;

int a[N], b[N], cnt[N * 20], vis[N], ans[N];
int sum, n, m, bklen;
int tot1, tot2;

struct query1
{
    int l, r, x, lb, rb, id;
    query1(){}
    query1(int l, int r, int x, int id) : l(l), r(r), x(x), id(id)
    {
        lb = (l - 1) / bklen + 1; rb = (r - 1) / bklen + 1;
    }
    bool operator < (const query1 &b) const
    {
        if (lb != b.lb) return lb < b.lb;
        if (rb != b.rb) return rb < b.rb;
        return x < b.x;
    }
}q1[N];
struct query2
{
    int pos, x, y;
    query2(){}
    query2(int pos, int x, int y) : pos(pos), x(x), y(y){}
}q2[N];

void update(int pos)
{
    if (vis[pos])
    {
        if (cnt[a[pos]] == 1) sum--;
        cnt[a[pos]]--;
    }
    else
    {
        if (cnt[a[pos]] == 0) sum++;
        cnt[a[pos]]++;  
    }
    vis[pos] ^= 1;
}
void change(int pos, int x)
{
    if (vis[pos])
    {
        update(pos);
        a[pos] = x;
        update(pos);
    }
    else a[pos] = x;
}
int main()
{
    cin.sync_with_stdio(0);
    cin >> n >> m;
    bklen = pow(n, 2.0 / 3);
    for (int i = 1; i <= n; ++i) cin >> a[i], b[i] = a[i];
    for (int i = 1; i <= m; ++i)
    {
        string s; int l, r;
        cin >> s >> l >> r; l++;
        if (s[0] == 'Q')
        {
            ++tot1; //如果写到下面的话,可能会导致后面的tot1没有+1
            q1[tot1] = query1(l, r, tot2, tot1);
        }
        else
        {
            q2[++tot2] = query2(l, b[l], r);
            b[l] = r;
        }
    }
    sort(q1 + 1, q1 + tot1 + 1);
    sum = 0;
    for (int i = 1, l = 1, r = 0, x = 0; i <= tot1; ++i)
    {
        while (x < q1[i].x) {++x; change(q2[x].pos, q2[x].y);}
        while (x > q1[i].x) {change(q2[x].pos, q2[x].x); --x;}
        while (r < q1[i].r) update(++r);
        while (r > q1[i].r) update(r--);
        while (l < q1[i].l) update(l++);
        while (l > q1[i].l) update(--l);
        ans[q1[i].id] = sum;
    }
    for (int i = 1; i <= tot1; ++i) cout << ans[i] << endl;
}


转载于:https://www.cnblogs.com/rpSebastian/p/7427976.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值