羅区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;
}