ツリーの議長-のダイナミックレンジ\(K \)小
ここでのテンプレートのタイトルロス・バレー2617。
まず、いくつかの質問のまとめを行います。
この記事を読ん間隔k番目のテンプレートのタイトルで、ある財団会長ツリーを、必要とします。
静的全体のk番目:
どのような小さなKを探しているのは、時間の複雑\(O(nlogn)\) 。
ダイナミック全体のk番目:
時間複雑で重量のセグメントツリーのメンテナンス\(O(nlogn)\) 。
静的間隔k番目:
会長ツリーのメンテナンス、時間複雑\(O(nlogn)\) 。
ダイナミックレンジのk番目:
これはタイトルです。
リコールは、木の会長は、まだk番目の間隔を維持していますか。
持続可能なツリーラインの確立後、k番目の思考クエリー間隔とプレフィックスを使用。
私たちは、動作範囲のk番目のバンド、接頭辞を変更したいので、キーです。
どのようなデータ構造を使用してメンテナンスや一般的な接頭辞、サポートの問い合わせや変更操作で私たち、?
- フェンウィックツリー/ツリーライン。
今回私たちは、一般的に、ツリーの動的会長と木の会長の概念持つデータ構造すでに多少異なる上を。
- 会長の動的なツリー:ツリーのカバーの木。
- 静的会長ツリー:永続的な重量区分の木も。
どのセットが問題ではなく、単に考える見つけることができ、我々は体重セグメントツリー(ルート)を維持するために、各ノード配列ツリー配列(内側の)層のための木を維持、我々はこの問題を解決することができます。
- 修理の操作:
- デジタルの位置場合\(a_iを= xは\)に変更(Y- \)\、次いで外側フェンウィックツリーに、我々は変更する必要があり、\(LOGNを\)ノード、および各ノードの(Aの代わりに重量セグメントツリー)、それぞれ\(logN個\)は、複雑さが変更されるので、影響を受けるノード\(O((logN個)^ 2)\) 。
- 検索操作:
- 毎\([L、R] \ ) 、レッツは、この間隔の間に抽出照会(LOGN \)\ルートノード、および、静的議長ツリーに求めて質問の範囲変換(K \)\小。
- 時間の複雑さはある\(O((logN個)^ 2)\) 。
総時間複雑そう\(O(N(LOGN) ^ 2)\) で。
次は、問題空間のいくつかを解決します。
私たちは、あるツリーラインスペースの複雑さを知っている(O(4N)\)\、つまり、\(O(N)\) 、フェンウィックツリーの複雑さがある(\ O(N))\そしてそうやって、スペースの複雑さに達した\(O(^ N-2)\) 。
最適化する方法を考えてみて?
私達はちょうど重量みなさ完全なセグメントツリーに基づいて、各ノードまで開くように、空間的な複雑さを計算します。
我々規模のクエリ/変更操作です\((LOGN)^ 2 \ ) レベル。
これは、動的に開いポイントではありません。
私たちのためにアクセスすることができ、そして問題に関することはできないノード作成、アクセスノードへ。
取り付け\(luogu2617 \)コード。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int n, m, a[maxn], b[maxn<<1], len;
struct Query
{
int op;
int i, j, k;
}q[maxn];
//1e5的log大概在20左右 20*20=400
int sum[maxn*400];
int ls[maxn*400];
int rs[maxn*400];
int rt[maxn*400];
int tot;
void update_SgT(int &rt, int l, int r, int x, int val)
{
if(!rt) rt = ++tot;
if(l == r)
{
sum[rt] += val;
return;
}
int mid = (l+r) >> 1;
if(x <= mid) update_SgT(ls[rt], l, mid, x, val);
else update_SgT(rs[rt], mid+1, r, x, val);
sum[rt] = sum[ls[rt]] + sum[rs[rt]];
}
inline int lowbit(int x){
return x&(-x);
}
void update_BIT(int pos, int x, int val)
{
for(int i = pos; i <= n; i += lowbit(i))
update_SgT(rt[i], 1, len, x, val);
}
///提取区间线段树的根节点
int rt1[maxn], rt2[maxn], cnt1, cnt2;
void locate(int l, int r)
{
cnt1 = cnt2 = 0;
for(int i = l-1; i; i -= lowbit(i))
rt1[++cnt1] = rt[i];
for(int i = r; i; i -= lowbit(i))
rt2[++cnt2] = rt[i];
}
int ask(int l, int r, int k)
{
if(l == r) return l;
int mid = (l+r) >> 1;
int suml = 0;
for(int i = 1; i <= cnt1; i++)
suml -= sum[ls[rt1[i]]];
for(int i = 1; i <= cnt2; i++)
suml += sum[ls[rt2[i]]];
if(suml >= k)
{
for(int i = 1; i <= cnt1; i++)
rt1[i] = ls[rt1[i]];
for(int i = 1; i <= cnt2; i++)
rt2[i] = ls[rt2[i]];
return ask(l, mid, k);
}
else
{
for(int i = 1; i <= cnt1; i++)
rt1[i] = rs[rt1[i]];
for(int i = 1; i <= cnt2; i++)
rt2[i] = rs[rt2[i]];
return ask(mid+1, r, k-suml);
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
b[++len] = a[i];
}
char op[2];
for(int i = 1; i <= m; i++)
{
scanf("%s", op);
if(op[0] == 'Q')
{
q[i].op = 0;
scanf("%d%d%d", &q[i].i, &q[i].j, &q[i].k);
}
else
{
q[i].op = 1;
scanf("%d%d", &q[i].i, &q[i].k);
b[++len] = q[i].k;
}
}
//数值离散化
sort(b+1, b+1+len);
len = unique(b+1, b+1+len)-b-1;
for(int i = 1; i <= n; i++)
a[i] = lower_bound(b+1, b+len+1, a[i])-b;
for(int i = 1; i <= m; i++)
if(q[i].op) q[i].k = lower_bound(b+1, b+len+1, q[i].k)-b;
//建树(动态开点形式)
for(int i = 1; i <= n; i++)
update_BIT(i, a[i], 1);
for(int i = 1; i <= m; i++)
{
if(q[i].op)
{
update_BIT(q[i].i, a[q[i].i], -1);
a[q[i].i] = q[i].k;
update_BIT(q[i].i, q[i].k, 1);
}
else
{
locate(q[i].i, q[i].j);
int ans = b[ask(1, len, q[i].k)];
printf("%d\n", ans);
}
}
return 0;
}