Codeforces 848C (cdq分治)

Codeforces 848C Goodbye Souvenir

Problem :
給一個長度爲n的序列,有q個詢問。一種詢問是修改某個位置的數,另外一種詢問是詢問一段區間,對於每一種值出現的最右端點的下標與最左端點的下標的差值求和。
Solution :
定義pre[i] 爲 第i個位置的數字上一次出現位置,對於詢問l, r 就是對於全部知足
l <= pre[i] < i <= r 的點求和,權值爲 i - pre[i]。
所以能夠把這個看做是三維偏序的問題,第一維時間,第二維,第三維pre[i], i,用cdq分治求解。
對每一種值開一個set進行預處理,把每一次修改形成的影響表示成 pre[i], i, val 的形式。node

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

const int N = 1e6 + 8;

int n, q, tot, num;
int a[N];
long long ans[N];
struct node
{
    int type, x, y, id;
    bool operator < (const node &b) const
    {
        return x < b.x || x == b.x && type < b.type;
    }
    void print()
    {
        cout << type << " " << x << " " << y << " " << id << endl;
    }  
}Q[N], tmp[N];
set <int> S[N];
struct BIT
{
    long long a[N];
    int len;
    void init(int l)
    {
        len = l;
        for (int i = 0; i < len; ++i) a[i] = 0;
    }
    void insert(int x, int y)
    {
        for (int i = x; i < len; i += i & (-i))
            a[i] += y;
    }
    long long query(int x)
    {
        long long res = 0;
        for (int i = x; i > 0; i -= i & (-i))
            res += a[i];
        return res;
    }
    void clear(int x)
    {
        for (int i = x; i < len; i += i & (-i))
            if (a[i] != 0) a[i] = 0; else break;
    }
}T;
void cdq(int l, int r)
{
    if (l == r) return; 
    int mid = l + r >> 1;
    cdq(l, mid);
    cdq(mid + 1, r);
    int i = l, j = mid + 1;
    for (int k = l; k <= r; ++k)
        if (j > r || i <= mid && Q[i] < Q[j])
        {
            tmp[k] = Q[i++];
            if (tmp[k].type == 1)
            {
                T.insert(n - tmp[k].y + 1, tmp[k].id);
            }
        }
        else
        {
            tmp[k] = Q[j++];
            if (tmp[k].type == 2)
            {
                ans[tmp[k].id] += T.query(n - tmp[k].y + 1);
            }
        }
    for (int k = l; k <= r; ++k) 
    {
        Q[k] = tmp[k];
        T.clear(n - tmp[k].y + 1);
    }
}
void update(int pos, int y)
{
    if (a[pos] == y) return;
    auto it = S[a[pos]].find(pos);
    auto it1 = it; it1--;
    auto it2 = it; it2++;
    Q[++tot] = (node){1, *it, *it1, *it1 - *it};
    Q[++tot] = (node){1, *it2, *it, *it - *it2};
    Q[++tot] = (node){1, *it2, *it1, *it2 - *it1};
    S[a[pos]].erase(pos);
    
    a[pos] = y; S[a[pos]].insert(pos);
    
    it = S[a[pos]].find(pos);
    it1 = it; it1--;
    it2 = it; it2++;
    Q[++tot] = (node){1, *it, *it1, *it - *it1};
    Q[++tot] = (node){1, *it2, *it, *it2 - *it};
    Q[++tot] = (node){1, *it2, *it1, *it1 - *it2};
}
void init()
{
    cin >> n >> q;
    tot = 0;
    for (int i = 1; i <= n; ++i) S[i].insert(0), S[i].insert(n + 1);
    for (int i = 1; i <= n; ++i)
    {
        int x; cin >> x; a[i] = x;
        S[x].insert(i);
        auto it = S[x].find(i);
        it--;
        Q[++tot] = (node){1, i, *it, i - (*it)};
    }
    num = 0;
    for (int i = 1; i <= q; ++i)
    {
        int type, x, y;
        cin >> type >> x >> y;
        if (type == 2)
        {
            Q[++tot] = (node){2, y, x, ++num};
        }
        else
        {
            update(x, y);
        }
    }
}
void solve()
{
    T.init(n + 10);
    cdq(1, tot);
    
    for (int i = 1; i <= num; ++i)
        cout << ans[i] << endl;
}
int main()
{
    cin.sync_with_stdio(0);
    init();
    solve();
}
相關文章
相關標籤/搜索