題目大意
一種數據結構,維護一個有序數列,其中需要提供以下操作:
1.查詢k在區間內的排名
2.查詢區間內排名爲k的值
3.修改某一位值上的數值
4.查詢k在區間內的前驅(前驅定義爲小於x,且最大的數)
5.查詢k在區間內的後繼(後繼定義爲大於x,且最小的數)
Solution
查詢k在的排名,k的前驅,後繼,能馬上想到用平衡樹維護。而因爲是在區間中詢問的,所以要用到樹套樹。外層維護一棵線段樹,內層平衡樹,就能查詢區間了。複雜度
而操作2,好像只能二分答案,再進行操作1,複雜度達到了令人絕望的
其實我們可以將內層的平衡樹替換爲一棵權值線段樹。同樣可以實現操作1和操作3,操作2時把這個區間包含的權值線段樹都拿出來,再一起二分,複雜度就變成了
考慮到一個問題,維護權值線段樹內存是
於是只好硬生生把原來在線的問題變成了離線。先進行離散化,把權值線段樹值域縮小,纔剛好夠了空間。空間是不是很絕望?
/**************************************************************
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;
}