羅区P1972定期/オフラインセグメントツリーのMo +カードチームの[SDOI2009] HHネックレス基盤

羅区P1972 [SDOI2009] HHネックレス

タグ

  • Mo基盤チーム
  • カード・チャン
  • セグメントツリーオフライン

序文

  • 私のブログのCSDNと庭園がようこそ、同期されdanzh-ブログパーク
  • これは、Moのチームの混乱の中で最も裸です。しかし、データが強化、のMo +チームが定期的にカードを生きるために酸素を必要とし、カードは、多くの場合、この記事の話、メインスピーカーのセグメントツリーは簡単です

質問の簡潔な意味

  • シーケンスには、各区間[L、R]多くの異なった数字は持っているかを尋ねます

考え

  • これは、Moのチームの混乱の中で最も裸です。しかし、データが強化、のMo +チームは〜通常のカード、その中に関連する操作の後、カードが多い書かれた要約を生きるために酸素を必要とします
  • そして、重みのセグメントツリーのメンテナンスと少ない暴力的な方法があります。(非常に巧妙なアヒル)
    -------------------------------------------- ----------分割線-------------------------------------鳩-----------------
  • まず、サンプルのグループを見てみましょう。

\ [1,2,4,5,2,4,2 \]

  • 私たちは、1に最終セットに同じ番号を入れて

\ [1,2,4,5,2,4,2 \]

\ [1,0,0,1,0,1,1 \]

  • それぞれが異なるだけ数字の数の数1、今必要な区間[L、R]を生成するので、直接行に番号1をカウントします。
  • 番号1が間違っている直接の統計上、それについて考えてみよう。たとえば、明らかに、上記の方法により求めたクエリ[3,3]は、0であるが、実際には1です。なぜ?実際には、上記の統計は正しいですが、クエリの右端が最後の番号である場合にのみ、左端のポイントはどんなことができますが、それは、右端点r = 7、(なぜ考える)に正しいことですA。
  • 右の時間が固定小数点の場合に明らかに、木のライン上にある何かが、維持保守間隔およびそれに見るために使用することができます。
  • 常に正しいポイントを尋ねるが、同じではありません。どのようにそれを行うには?思考の会長は、木を利用することができ、右のポイントごとの動きは、あなたが現在の間隔とrを確保するために、現在のツリーライン、ツリーラインのメンテナンスについて更新します。
  • だから、並べ替えに合わせて、ツリーラインについての最初の更新の各右端ポイント増加、クエリを右の点をお尋ねし、オフラインにする必要があります。
  • 最後に5 = Iを更新するなど、更新ツリーラインについて話しています。だから、01シーケンスは、その後2〜52の番号の前に置き、1に5である必要があり、セグメントツリーは、彼が0だから我々は、[I]あたりの個数治療の前にする必要がありますです彼の前のテーブルに同じ番号なので、この問題は、ACことができます

注意事項

  • ノー

概要

Moのチームセクション

  • 高速の読み取りと書き込み
inline int read()
{
    int ans = 0;
    char r = getchar(); bool neg = false;
    while (r<'0' || r>'9') { if (r == '-')neg = true; r = getchar(); }
    while (r >= '0'&&r <= '9') { ans = ans * 10 + r - '0'; r = getchar(); }
    return (neg) ? -ans : ans;
}
void write(int x) {
    if (x < 0) { putchar('-'); x = -x; }
    if (x > 9)write(x / 10);
    putchar(x % 10 + '0');
}//write不带换行符,需要自己putchar('\n')
  • ソートパリティ
bool operator < (const Query& a)const
{
    return pos[l] ^ pos[a.l] ? pos[l] < pos[a.l] : pos[l] & 1 ? r<a.r : r>a.r;
}
  • ブロックのサイズ
int len =  n / sqrt(n * 2 / 3);

セグメントツリーセクション

  • このメソッドは、常にオフラインツリーラインを考えることができるはずです〜

ACコード

Moのチーム

#pragma GCC optimize(2)
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

inline int read()
{
    int ans = 0;
    char r = getchar(); bool neg = false;
    while (r<'0' || r>'9') { if (r == '-')neg = true; r = getchar(); }
    while (r >= '0'&&r <= '9') { ans = ans * 10 + r - '0'; r = getchar(); }
    return (neg) ? -ans : ans;
}
void write(int x) {
    if (x < 0) { putchar('-'); x = -x; }
    if (x > 9)write(x / 10);
    putchar(x % 10 + '0');
}

const int maxn = 1e6 + 10;

int pos[maxn];
struct Query
{
    int l, r, id;
    bool operator < (const Query& a)const
    {
        return pos[l] ^ pos[a.l] ? pos[l] < pos[a.l] : pos[l] & 1 ? r<a.r : r>a.r;
    }
};
Query query[maxn];

int n, q, a[maxn];

int ans, cnt[maxn];

int ans0[maxn];
void solve()
{
    scanf("%d", &n);
    int len =  n / sqrt(n * 2 / 3);
    for (int i = 1; i <= n; i++)
        a[i] = read(), pos[i] = (i - 1) / len + 1;
    scanf("%d", &q);
    for (int i = 1; i <= q; i++)
        query[i].l = read(), query[i].r = read(), query[i].id = i;
    sort(query + 1, query + 1 + q);

    int l = 1, r = 0;
    for (int i = 1; i <= q; i++)
    {
        int L = query[i].l, R = query[i].r;
        while (l < L) if (cnt[a[l++]]-- == 1) ans--;
        while (l > L)if (cnt[a[--l]]++ == 0) ans++;
        while (r < R) if (cnt[a[++r]]++ == 0) ans++;
        while (r > R) if (cnt[a[r--]]-- == 1) ans--;

        ans0[query[i].id] = ans;
    }

    for (int i = 1; i <= q; i++)
        write(ans0[i]), putchar('\n');
}

int main()
{
    //freopen("Testin.txt", "r", stdin);
    solve();
    return 0;
}

セグメントツリー

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 1e6 + 10;

struct Query
{
    int l, r, id;
    bool operator < (const Query& a)const
    {
        return r < a.r;
    }
};Query query[maxn];

struct Node
{
    int l, r, sum;
}; Node tree[maxn * 4];

void build(int o, int l, int r)
{
    tree[o].l = l, tree[o].r = r;
    if (l == r)
        return;
    int mid = (l + r) / 2;
    build(o * 2, l, mid);
    build(o * 2 + 1, mid + 1, r);
}

void change(int o, int x, int type)
{
    if (tree[o].l == tree[o].r)
    {
        tree[o].sum = type;
        return;
    }
    
    int mid = (tree[o].l + tree[o].r) / 2;
    if (x <= mid)
        change(o * 2, x, type);
    else
        change(o * 2 + 1, x, type);

    tree[o].sum = tree[o * 2].sum + tree[o * 2 + 1].sum;
}

int ask(int o, int l, int r)
{
    if (tree[o].l == l && tree[o].r == r)
        return tree[o].sum;

    int mid = (tree[o].l + tree[o].r) / 2;
    if (r <= mid)
        return ask(o * 2, l, r);
    else if (l > mid)
        return ask(o * 2 + 1, l, r);
    return ask(o * 2, l, mid) + ask(o * 2 + 1, mid + 1, r);
}

int n, q, a[maxn];

int ans0[maxn];
int las[maxn], pos[maxn];
void solve()
{
    build(1, 1, maxn - 10);
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]), las[i] = pos[a[i]], pos[a[i]] = i;
    scanf("%d", &q);
    for (int i = 1; i <= q; i++)
        scanf("%d%d", &query[i].l, &query[i].r), query[i].id = i;
    sort(query + 1, query + 1 + q);

    int las_r = 1;
    for (int i = 1; i <= q; i++)
    {
        int l = query[i].l, r = query[i].r;
        for (int i = las_r; i <= r; i++)
        {
            if (las[i] != 0)
                change(1, las[i], 0);
            change(1, i, 1);
        }
            
        ans0[query[i].id] = ask(1, l, r);
        las_r = r + 1;
    }

    for (int i = 1; i <= q; i++)
        printf("%d\n", ans0[i]);
}

int main()
{
    freopen("Testin.txt", "r", stdin);
    solve();
    return 0;
}

おすすめ

転載: www.cnblogs.com/danzh/p/11323029.html