P1903 [全国トレーニングチーム]変更されたMoチーム

題名

ポータルP1903【全国研修チーム】色数/メンテナンスキュー

回答

通常のMoチームと比較して、変更操作に対応する時間軸がもう1つあります。各クエリは、2次元(l、r)(l、r)で構成されます。l r は3次元になります(l、r、t)(l、r、t)l r t 基本的な考え方は、最初のw − 1w-1をクエリすることです。w1次元ブロックであるため、前面w − 1 w-1wブロック内の1次元値の範囲が制限されているため、wwthwディメンションはブロック内で順序付けられており、この時点で各クエリをより短いルートでトラバースできます。

具体的には、クエリ間隔[1、N] [1、N][ 1 N ]は、l、r、tl、r、tのブロックに分割されますl r tは、1番目、2番目、および3番目のキーワードの順序です。クエリ数を設定するQQQ.変更TTTNNNは同じ大きさです。[1、N] [1、N]とします。[ 1 N ]aaに分けられますその後、ブロック、LLlはブロックにaaがありますa 种, r r rはブロックにaaを持っていますa入力すると、ブロックの総数は2 a ^ 2になります。a2同じブロックで、tttが単調である場合、各ブロック境界で時間軸が変更される回数はO(N)O(N)です。O N 、各ブロック内の変更回数はO(N)O(N)O N 、変更の総数はO(a 2 N)O(a ^ 2N)O a2 Nl、rl、rl ブロック内のrの最大値と最小値差はO(N / a)O(N / a)です。O N / a 、ブロック間で変更O(N)O(N)O N 、変更の総数O(N×N / a + a 2 N)O(N \ times N / a + a ^ 2N)O N××N / a+a2 NN2 / a = a 2 NN ^ 2 / a = a ^ 2NによってN2 /a=a2 N、ブロック数はN 1/3 N ^ {1/3}N1 / 3、ブロックサイズN 2/3 N ^ {2/3N2 / 3

最適化にはパリティソートを使用できます。基本的な原理は、ブロックの最後の次元、つまりw − 1w-1を除算することです。w1次元の奇数ブロックからwww次元の昇順ソート、偶数ブロックwww次元の降順でソートし、ww隣接するブロック間のw次元の変更回数は減少する可能性があります。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 133335, maxc = 1000005;
int N, M, qn, rn, res, id[maxn], col[maxn], rec[maxn], cnt[maxc];
struct P1
{
    
    
    int l, r, t, k;
    bool operator<(const P1 &b) const
    {
    
    
        if (id[l] != id[b.l])
            return l < b.l;
        if (id[r] != id[b.r])
            return r < b.r;
        return (id[r] & 1) ? t < b.t : t > b.t;
    }
} Q[maxn];
struct P2
{
    
    
    int k, c;
} R[maxn];

inline int read()
{
    
    
    int x = 0;
    char c = 0;
    for (; c < '0' || c > '9'; c = getchar())
        ;
    for (; c >= '0' && c <= '9'; c = getchar())
        x = (x << 1) + (x << 3) + c - '0';
    return x;
}

inline void add(int i)
{
    
    
    if (!cnt[col[i]]++)
        ++res;
}

inline void del(int i)
{
    
    
    if (!--cnt[col[i]])
        --res;
}

inline void upd(int t, int i)
{
    
    
    int p = R[t].k;
    if (Q[i].l <= p && p <= Q[i].r)
        del(p), swap(col[p], R[t].c), add(p);
    else
        swap(col[p], R[t].c);
}

int main()
{
    
    
    N = read(), M = read();
    for (int i = 1; i <= N; ++i)
        col[i] = read();
    for (int i = 1; i <= M; ++i)
    {
    
    
        char op;
        scanf(" %c", &op);
        if (op == 'Q')
            Q[++qn] = P1{
    
    read(), read(), rn, qn};
        else
            R[++rn] = P2{
    
    read(), read()};
    }
    int w = pow(N, 2.0 / 3.0), t = ceil((double)N / w);
    for (int i = 1; i <= t; ++i)
        for (int l = (i - 1) * w + 1, r = min(i * w, N), j = l; j <= r; ++j)
            id[j] = i;
    sort(Q + 1, Q + qn + 1);
    for (int i = 1, l = Q[1].l, r = l - 1, t = 0, ql, qr, qt; i <= qn; ++i)
    {
    
    
        ql = Q[i].l, qr = Q[i].r, qt = Q[i].t;
        while (l < ql)
            del(l++);
        while (l > ql)
            add(--l);
        while (r < qr)
            add(++r);
        while (r > qr)
            del(r--);
        while (t < qt)
            upd(++t, i);
        while (t > qt)
            upd(t--, i);
        rec[Q[i].k] = res;
    }
    for (int i = 1; i <= qn; ++i)
        printf("%d\n", rec[i]);
    return 0;
}

おすすめ

転載: blog.csdn.net/neweryyy/article/details/114435096