赵队牛逼!!!!!
题目内容
对一个序列进行两种操作:
-
修改第 个数为
-
查询区间 第 小的数
分析
对于不待修改的区间第 小,我们可以用主席树完成。
我们来看看只用主席树如何完成带修改的区间第 小。
对于每次修改,我们都需要把当前位置及以后的主席树都进行修改。因此每次修改的时间复杂度为 ,空间增加 , 次操作直接爆炸。查询操作依旧是 。
下面考虑加上树状数组后的情况。
我们把树状数组的每个点都改为一棵主席树,树状数组的每次修改操作都需要修改 个节点,由于每个节点都是主席树,所以每次修改时间复杂度为 ,空间增加 ,比较优秀。
注:此题还需要离散化
如何实现树状数组套主席树
普通主席树中第 棵主席树维护的是 这段区间的权值信息。
而树状数组套主席树中的第 棵主席树,维护树状数组中第 个点所维护的点的权值信息,即: 在普通树状数组第 个点维护 节点 的和。那么树状数组套主席树的第 个点就维护节点 的权值信息。
代码
空间要开很大(此处感谢赵队)
只用待修的主席树常数较大,姿势不对就会超时。
正确操作:
普通主席书维护原序列的信息,带修改的主席树维护修改的信息
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 20;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
int cnt = 0, S[maxn],T[maxn], L[maxn << 8], R[maxn << 8], sum[maxn << 8];
int build(int l, int r)
{
int rt = ++cnt;
sum[rt] = 0;
if (l < r)
{
int mid = (l + r) >> 1;
L[rt] = build(l, mid);
R[rt] = build(mid + 1, r);
}
return rt;
}
int update(int pre, int l, int r, int x, int val)
{
int rt = ++cnt;
L[rt] = L[pre];
R[rt] = R[pre];
sum[rt] = sum[pre] + val;
if (l < r)
{
int mid = (l + r) >> 1;
if (x <= mid)
L[rt] = update(L[pre], l, mid, x, val);
else
R[rt] = update(R[pre], mid + 1, r, x, val);
}
return rt;
}
int lowbit(int x)
{
return x & (-x);
}
int used[maxn],n,m;
void add(int x, int pos, int val)
{
for (int i = pos; i <= n; i += lowbit(i))
S[i] = update(S[i], 0, 2e5 + 10, x, val);
}
int query(int t1,int t2,int u, int v, int l, int r, int k)
{
if (l >= r)
return l;
int s = 0, mid = (r + l) >> 1;
for (int i = v; i > 0; i -= lowbit(i))
s += sum[L[used[i]]];
for (int i = u; i > 0; i -= lowbit(i))
s+=sum[L[t2]]-sum[L[t1]];
if (s >= k)
{
for (int i = v; i > 0; i -= lowbit(i))
used[i] = L[used[i]];
for (int i = u; i > 0; i -= lowbit(i))
used[i] = L[used[i]];
return query(L[t1],L[t2],u, v, l, mid, k);
}
else
{
for (int i = v; i > 0; i -= lowbit(i))
used[i] = R[used[i]];
for (int i = u; i > 0; i -= lowbit(i))
used[i] = R[used[i]];
return query(R[t1],R[t2],u, v, mid + 1, r, k - s);
}
}
struct node
{
char id;
int l,r,data;
}q[maxn];
int book[maxn],h[maxn];
int gethash(int x,int len)
{
return lower_bound(h,h+len,x)-h;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int now=0;
T[0] = build(0, 2e5 + 10);
for(int i=0;i<=n;i++) S[i]=T[0];
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> book[i],h[now++]=book[i];
for(int i=0;i<m;i++)
{
char id;
cin >> id;
if (id == 'C')
{
int pos, x;
cin >> pos >> x;h[now++]=x;
q[i].id='C',q[i].l=pos,q[i].data=x;
}
else if (id == 'Q')
{
int l, r, k;
cin >> l >> r >> k;
q[i].id='Q',q[i].l=l,q[i].r=r,q[i].data=k;
}
}
sort(h,h+now);
int num=unique(h,h+now)-h;
for(int i=1;i<=n;i++)T[i]=update(T[i-1],0,2e5+10,gethash(book[i],num),1);
for(int i=0;i<m;i++)
{
if(q[i].id=='C')
{
add(gethash(book[q[i].l],num),q[i].l,-1);
add(gethash(q[i].data,num),q[i].l,1);
book[q[i].l]=q[i].data;
}
else if(q[i].id=='Q')
{
for(int j=q[i].r;j>0;j-=lowbit(j)) used[j]=S[j];
for(int j=q[i].l-1;j>0;j-=lowbit(j)) used[j]=S[j];
int pos=query(T[q[i].l-1],T[q[i].r],q[i].l-1,q[i].r,0,2e5+10,q[i].data);
cout<<h[pos]<<'\n';
}
}
return 0;
}