标签:modify efi merge def 线段树 ima ++ 条件 nbsp
人生第一次写树套树
这题是区间上的数值操作,所以我们用区间数据结构套数值数据结构
我选择了线段树套splay
其实就是对于线段树的每个节点$x$,若它代表的区间为$[l,r]$,则在这个线段树节点上建一棵含$A_{l\cdots r}$的splay
对$1$操作:直接按线段树的方式把$[l,r]$分为一些区间,在每个区间内找比$k$小的数的个数,最后$+1$即可
对$2$操作:二分答案,将$1$操作作为二分条件
对$3$操作:按线段树单点修改的方式,每到一个线段树节点就在当前的splay上删除$A_pos$再插入$k$
对$4$操作:按线段树的方式分割区间,找每个区间内$k$的前驱,最后取最大值为答案
对$5$操作:按线段树的方式分割区间,找每个区间内$k$的后继,最后取最小值为答案
interesting

#include<stdio.h>
int root[200010],a[50010],ch[1600010][2],fa[1600010],siz[1600010],v[1600010],tot,n,*rt;
void rot(int x){
int y,z,B,f;
y=fa[x];
z=fa[y];
if(y==*rt)*rt=x;
f=(ch[y][0]==x);
B=ch[x][f];
fa[x]=z;
fa[y]=x;
if(B)fa[B]=y;
ch[x][f]=y;
ch[y][f^1]=B;
if(ch[z][0]==y)ch[z][0]=x;
if(ch[z][1]==y)ch[z][1]=x;
z=siz[x];
siz[x]=siz[y];
siz[y]-=(z-siz[B]);
}
void splay(int x){
int y,z;
while(x!=*rt){
y=fa[x];
z=fa[y];
if(y==*rt)
rot(x);
else{
if((ch[y][0]==x&&ch[z][0]==y)||(ch[y][1]==x&&ch[z][1]==y)){
rot(y);
rot(x);
}else{
rot(x);
rot(x);
}
}
}
}
int _insert(int&x,int val){
if(x==0){
tot++;
x=tot;
v[x]=val;
}
siz[x]++;
int k=x;
if(val<v[x]){
k=_insert(ch[x][0],val);
fa[ch[x][0]]=x;
}
if(val>v[x]){
k=_insert(ch[x][1],val);
fa[ch[x][1]]=x;
}
return k;
}
void insert(int&x,int val){
splay(_insert(x,val));
}
void build(int l,int r,int x){
rt=root+x;
for(int i=l;i<=r;i++)insert(root[x],a[i]);
if(l==r)return;
int mid=(l+r)>>1;
if(l<=mid)build(l,mid,x<<1);
if(mid<r)build(mid+1,r,x<<1|1);
}
int max(int a,int b){return a>b?a:b;}
int getrank(int x,int val){
if(x==0)return 0;
if(val<v[x])return getrank(ch[x][0],val);
if(val>v[x])return max(getrank(ch[x][1],val),0)+siz[x]-siz[ch[x][1]];
return siz[ch[x][0]];
}
int getrank(int L,int R,int val,int l,int r,int x){
if(L<=l&&r<=R){
rt=root+x;
return getrank(root[x],val);
}
int mid=(l+r)>>1,ans=0;
if(L<=mid)ans+=getrank(L,R,val,l,mid,x<<1);
if(mid<R)ans+=getrank(L,R,val,mid+1,r,x<<1|1);
return ans;
}
int getkth(int l,int r,int k){
int L,R,mid,ans;
L=-100000000;
R=100000000;
while(L<=R){
mid=(L+R)>>1;
if(getrank(l,r,mid,1,n,1)+1<=k){
L=mid+1;
ans=mid;
}else
R=mid-1;
}
return ans;
}
void merge(int a,int b){
if(a==0){
*rt=b;
return;
}
*rt=a;
if(b==0)return;
while(ch[a][1])a=ch[a][1];
splay(a);
ch[a][1]=b;
siz[a]+=siz[b];
fa[b]=a;
}
void erase(int x,int val){
if(val==v[x]){
splay(x);
if(siz[x]-siz[ch[x][0]]-siz[ch[x][1]]>1){
siz[x]--;
return;
}
fa[ch[x][0]]=fa[ch[x][1]]=0;
siz[x]=0;
merge(ch[x][0],ch[x][1]);
ch[x][0]=ch[x][1]=0;
return;
}
if(val<v[x])erase(ch[x][0],val);
if(val>v[x])erase(ch[x][1],val);
}
void modify(int pos,int val,int l,int r,int x){
rt=root+x;
erase(root[x],a[pos]);
insert(root[x],val);
if(l==r)return;
int mid=(l+r)>>1;
if(pos<=mid)
modify(pos,val,l,mid,x<<1);
else
modify(pos,val,mid+1,r,x<<1|1);
}
#define inf 1000000000
int presc(int x,int val){
int ans=-inf;
while(x){
if(v[x]<val){
ans=v[x];
x=ch[x][1];
}else
x=ch[x][0];
}
return ans;
}
int presc(int L,int R,int val,int l,int r,int x){
if(L<=l&&r<=R)return presc(root[x],val);
int ans=-inf,mid=(l+r)>>1;
if(L<=mid)ans=max(ans,presc(L,R,val,l,mid,x<<1));
if(mid<R)ans=max(ans,presc(L,R,val,mid+1,r,x<<1|1));
return ans;
}
int nexsc(int x,int val){
int ans=inf;
while(x){
if(v[x]>val){
ans=v[x];
x=ch[x][0];
}else
x=ch[x][1];
}
return ans;
}
int min(int a,int b){return a<b?a:b;}
int nexsc(int L,int R,int val,int l,int r,int x){
if(L<=l&&r<=R)return nexsc(root[x],val);
int ans=inf,mid=(l+r)>>1;
if(L<=mid)ans=min(ans,nexsc(L,R,val,l,mid,x<<1));
if(mid<R)ans=min(ans,nexsc(L,R,val,mid+1,r,x<<1|1));
return ans;
}
int main(){
int m,i,op,l,r,k;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",a+i);
build(1,n,1);
while(m--){
scanf("%d%d%d",&op,&l,&r);
if(op!=3)scanf("%d",&k);
if(op==1)printf("%d\n",getrank(l,r,k,1,n,1)+1);
if(op==2)printf("%d\n",getkth(l,r,k));
if(op==3){
modify(l,r,1,n,1);
a[l]=r;
}
if(op==4)printf("%d\n",presc(l,r,k,1,n,1));
if(op==5)printf("%d\n",nexsc(l,r,k,1,n,1));
}
}
标签:modify efi merge def 线段树 ima ++ 条件 nbsp
原文地址:http://www.cnblogs.com/jefflyy/p/7630582.html