树状数组套可持久化线段树
Solution
我们现在先只使用主席树。
那么每次修改都要把版本 (x) 的树枝挪一挪。 (O(log n)) 可以解决挪动。
但是会影响到之后版本的树的 Size ,如果全部改掉最多需要 (O(nlog^2 n))
这是万万不行的。
为什么会影响到之后版本树的 Size ?
先来看一个问题。主席树的每个版本只有 (log n) 个结点吗?
不是吧。那是什么呢?是之前所有版本的前缀和。
Size 同样,也是前缀和。
前缀和可以用树状数组维护、
那么,只需要把 主席树的版本 当成 树状数组的一个数 就可以了
树状数组维护的 (2^i) 长度区间的和,在树套树意义下就是 (2^i) 个版本的,主席树的和。
当然,因为“加一个版本主席树”的操作等同于“加一条链”,所以其实等同于插入一个数。
然后你会发现所谓的主席树就是一个谎言,我们套的其实是好多捆线段树的链
但是,虽然没有往前面的版本连线,
这个东西的基本思想仍然有可持久化线段树的部分,不过用了另一种方式维护多个版本的总和。
……但是省空间的部分就完全不一样了。
标签打多了,有时候把某个算法改动一下,总会有套不上的时候嘛。
时空复杂度 (O(nlog^2 n))
查询的场合,在两个版本上同时跑。
因为要统计前缀和,所以要带上减去不同次 lowbit 的那一串不同版本的主席树。
把询问的下标当作查询的位置居然过了样例..
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 1e5 + 10;
#define lowbit(i) ((i)&-(i))
int n, m;
int a[MAXN];
int EL[MAXN<<1]={};
struct Operat
{
bool t;
int l, r, x;
Operat(bool tt=0, int ll=0, int rr=0, int xx=0)
{
t = tt;
l = ll;
r = rr;
x = xx;
}
}Op[MAXN];
int SegTot = 0;
int Rt[MAXN<<8];
int Lc[MAXN<<8], Rc[MAXN<<8];
int Size[MAXN<<8];
//Mei You Int Size MAXN
void PersisTree_Add(int &Pos, int L, int R, int Val, int Add) //NO PREPOS
{
if (!Pos) Pos = ++SegTot;
Size[Pos] += Add;
if (L == R) return;
int Mid = L + R >> 1;
if (Val <= Mid)
{
PersisTree_Add(Lc[Pos], L, Mid, Val, Add);
}
else
{
PersisTree_Add(Rc[Pos], Mid + 1, R, Val, Add);
}
}
void BIT_Add(int Pos, int Val, int Opt)
{
while (Pos <= n)
{
PersisTree_Add(Rt[Pos], 1, EL[0], Val, Opt);
Pos += lowbit(Pos);
}
}
int ListL[500], ListR[500];
#define LUP for (int i = 1; i <= ListL[0]; ++i)
#define RUP for (int i = 1; i <= ListR[0]; ++i)
int Qkth(int l, int r, int k)
{
if (l == r) return l;
int Mid = l + r >> 1;
int LeftSiz = 0;
RUP {
LeftSiz += Size[Lc[ListR[i]]];
}
LUP {
LeftSiz -= Size[Lc[ListL[i]]];
}
if (k <= LeftSiz)
{
LUP ListL[i] = Lc[ListL[i]];
RUP ListR[i] = Lc[ListR[i]];
return Qkth(l, Mid, k);
}
// else
LUP ListL[i] = Rc[ListL[i]];
RUP ListR[i] = Rc[ListR[i]];
return Qkth(Mid + 1, r, k - LeftSiz);
}
int BIT_SumAndKth(int l, int r, int k)
{
--l;
ListL[0] = ListR[0] = 0;
while(l)
{
ListL[++ListL[0]] = Rt[l];
l -= lowbit(l);
}
while(r)
{
ListR[++ListR[0]] = Rt[r];
r -= lowbit(r);
}
return Qkth(1, EL[0], k);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
EL[++EL[0]] = a[i];
}
char ch;
for (int ar1, ar2, ar3, i = 1; i <= m; ++i)
{
cin >> ch >> ar1 >> ar2;
if (ch == 'Q')
{
cin >> ar3;
Op[i] = Operat(0, ar1, ar2, ar3);
continue;
}
Op[i] = Operat(1, ar1, 0, ar2);
EL[++EL[0]] = ar2;
}
sort(EL + 1, EL + 1 + EL[0]);
EL[0] = unique(EL + 1, EL + 1 + EL[0]) - EL - 1;
for (int tem, i = 1; i <= n; ++i)
{
tem = lower_bound(EL + 1, EL + 1 + EL[0], a[i]) - EL;
a[i] = tem;
BIT_Add(i, tem, +1);
}
for (int tem, i = 1; i <= m; ++i)
{
if (Op[i].t) // C x y
{
tem = lower_bound(EL + 1, EL + 1 + EL[0], Op[i].x) - EL;
BIT_Add(Op[i].l, a[Op[i].l], -1); // Notice !! a[] NOT a[i] orzrzrzrzrz
a[Op[i].l] = tem;
BIT_Add(Op[i].l, tem, +1);
continue;
}
// Q l r k
cout << EL[BIT_SumAndKth(Op[i].l, Op[i].r, Op[i].x)] << endl;
}
return 0;
}