题目大意
一种数据结构,维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
Solution
查询k在的排名,k的前驱,后继,能马上想到用平衡树维护。而因为是在区间中询问的,所以要用到树套树。外层维护一棵线段树,内层平衡树,就能查询区间了。复杂度
(logn)2
。
而操作2,好像只能二分答案,再进行操作1,复杂度达到了令人绝望的
(logn)3
……
其实我们可以将内层的平衡树替换为一棵权值线段树。同样可以实现操作1和操作3,操作2时把这个区间包含的权值线段树都拿出来,再一起二分,复杂度就变成了
(logn)2
。操作4和5有点麻烦,但是前驱可以通过操作1和2得到,后继也同理。我们就能维护所有操作了。总时间复杂度
nlogn2
。
考虑到一个问题,维护权值线段树内存是
nlogn
,整颗树的内存就变成了
nlogn2
,而BZOJ上内存只给了128MB,只能开3个10000000的数组,根本过不了TT。
于是只好硬生生把原来在线的问题变成了离线。先进行离散化,把权值线段树值域缩小,才刚好够了空间。空间是不是很绝望?
/**************************************************************
Problem: 3196
Language: C++
Result: Accepted
Time:4916 ms
Memory:120984 kb
****************************************************************/
#include<cstdio>
#include<algorithm>
using namespace std;
int cnt,lson[10000010],rson[10000010],tree[10000010];
int root[200010],a[50010],q[10010];
int Small,Max,ta,b[100010],O[50010],l[50010],r[50010],k[50010],val[200010];
void insert(int &u,int l,int r,int key)
{
if (!u) u=++cnt;
if (l==r)
{
tree[u]++;
return;
}
int mid=(l+r)>>1;
if (key<=mid) insert(lson[u],l,mid,key);
else insert(rson[u],mid+1,r,key);
tree[u]=tree[lson[u]]+tree[rson[u]];
}
void build(int l,int r,int t)
{
for (int i=l;i<=r;i++)
insert(root[t],0,100000,a[i]);
if (l==r)
{
return;
}
int mid=(l+r)>>1;
build(l,mid,t<<1);
build(mid+1,r,t<<1|1);
}
void query_small(int t,int l,int r,int x,int y)
{
if (!t) return;
if (l==x&&y==r)
{
Small+=tree[t];
return;
}
int mid=(l+r)>>1;
if (y<=mid) query_small(lson[t],l,mid,x,y);
else if (x>mid) query_small(rson[t],mid+1,r,x,y);
else query_small(lson[t],l,mid,x,mid),query_small(rson[t],mid+1,r,mid+1,y);
}
void query_randmin(int l,int r,int x,int y,int t,int key)
{
if (l==x&&y==r)
{
query_small(root[t],0,100000,0,key-1);
return;
}
int mid=(l+r)>>1;
if (y<=mid) query_randmin(l,mid,x,y,t<<1,key);
else if (x>mid) query_randmin(mid+1,r,x,y,t<<1|1,key);
else query_randmin(l,mid,x,mid,t<<1,key),query_randmin(mid+1,r,mid+1,y,t<<1|1,key);
}
void query_queue(int l,int r,int x,int y,int t)
{
if (l==x&&y==r)
{
q[++ta]=root[t];
return;
}
int mid=(l+r)>>1;
if (y<=mid) query_queue(l,mid,x,y,t<<1);
else if (x>mid) query_queue(mid+1,r,x,y,t<<1|1);
else query_queue(l,mid,x,mid,t<<1),query_queue(mid+1,r,mid+1,y,t<<1|1);
}
int query_rand(int l,int r,int k)
{
if (l==r) return l;
int mid=(l+r)>>1;
int sum=0;
for (int i=1;i<=ta;i++)
sum+=tree[lson[q[i]]];
if (k<=sum)
{
for (int i=1;i<=ta;i++) q[i]=lson[q[i]];
return query_rand(l,mid,k);
}
else
{
for (int i=1;i<=ta;i++) q[i]=rson[q[i]];
return query_rand(mid+1,r,k-sum);
}
}
void query_max(int t,int l,int r,int x,int y)
{
if (!t) return;
if (l==x&&y==r)
{
Max+=tree[t];
return;
}
int mid=(l+r)>>1;
if (y<=mid) query_max(lson[t],l,mid,x,y);
else if (x>mid) query_max(rson[t],mid+1,r,x,y);
else query_max(lson[t],l,mid,x,mid),query_max(rson[t],mid+1,r,mid+1,y);
}
void query_randmax(int l,int r,int x,int y,int t,int key)
{
if (l==x&&y==r)
{
query_max(root[t],0,100000,key+1,100000);
return;
}
int mid=(l+r)>>1;
if (y<=mid) query_randmax(l,mid,x,y,t<<1,key);
else if (x>mid) query_randmax(mid+1,r,x,y,t<<1|1,key);
else query_randmax(l,mid,x,mid,t<<1,key),query_randmax(mid+1,r,mid+1,y,t<<1|1,key);
}
int query_rands(int l,int r,int k)
{
if (l==r) return l;
int mid=(l+r)>>1;
int sum=0;
for (int i=1;i<=ta;i++)
sum+=tree[rson[q[i]]];
if (k<=sum)
{
for (int i=1;i<=ta;i++)
q[i]=rson[q[i]];
return query_rands(mid+1,r,k);
}
else
{
for (int i=1;i<=ta;i++)
q[i]=lson[q[i]];
return query_rands(l,mid,k-sum);
}
}
void ins(int &t,int l,int r,int key,int Add)
{
if (!t) t=++cnt;
if (l==r)
{
tree[t]+=Add;
return;
}
int mid=(l+r)>>1;
if (key<=mid) ins(lson[t],l,mid,key,Add);
else ins(rson[t],mid+1,r,key,Add);
tree[t]=tree[lson[t]]+tree[rson[t]];
}
void modify(int l,int r,int t,int pos,int key,int Add)
{
if (l==r)
{
ins(root[t],0,100000,key,Add);
return;
}
int mid=(l+r)>>1;
if (pos<=mid) modify(l,mid,t<<1,pos,key,Add);
else modify(mid+1,r,t<<1|1,pos,key,Add);
ins(root[t],0,100000,key,Add);
}
int main()
{
//freopen("data10.in","r",stdin);
//freopen("data10.out","w",stdout);
int n,m,cc=0;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[++cc]=a[i];
}
for (int i=1;i<=m;i++)
{
scanf("%d",&O[i]);
if (O[i]==1) scanf("%d%d%d",&l[i],&r[i],&k[i]),b[++cc]=k[i];
if (O[i]==2) scanf("%d%d%d",&l[i],&r[i],&k[i]);
if (O[i]==3) scanf("%d%d",&l[i],&k[i]),b[++cc]=k[i];
if (O[i]==4) scanf("%d%d%d",&l[i],&r[i],&k[i]),b[++cc]=k[i];
if (O[i]==5) scanf("%d%d%d",&l[i],&r[i],&k[i]),b[++cc]=k[i];
}
sort(b+1,b+1+cc);
int n1=unique(b+1,b+1+cc)-b-1;
for (int i=1;i<=n;i++)
{
int xx=lower_bound(b+1,b+1+n1,a[i])-b;
val[xx]=a[i],a[i]=xx;
}
for (int i=1;i<=m;i++)
if (O[i]!=2)
{
int xx=lower_bound(b+1,b+1+n1,k[i])-b;
val[xx]=k[i],k[i]=xx;
}
build(1,n,1);
for (int i=1;i<=m;i++)
{
if (O[i]==1)
{
Small=0;
query_randmin(1,n,l[i],r[i],1,k[i]);
printf("%d\n",Small+1);
}
if (O[i]==2)
{
ta=0;
query_queue(1,n,l[i],r[i],1);
printf("%d\n",val[query_rand(0,100000,k[i])]);
}
if (O[i]==3)
{
//if (a[l[i]]==k[i]) continue;
modify(1,n,1,l[i],a[l[i]],-1);
modify(1,n,1,l[i],k[i],1);
a[l[i]]=k[i];
}
if (O[i]==4)
{
Small=0;
query_randmin(1,n,l[i],r[i],1,k[i]);
ta=0;
query_queue(1,n,l[i],r[i],1);
printf("%d\n",val[query_rand(0,100000,Small)]);
}
if (O[i]==5)
{
Max=0;
query_randmax(1,n,l[i],r[i],1,k[i]);
ta=0;
query_queue(1,n,l[i],r[i],1);
printf("%d\n",val[query_rands(0,100000,Max)]);
}
}
return 0;
}