树套树
省选前想把CTSC2008树链剖分+区间线段数+权值平衡树写出来,但是失败了,代码也找不到了,于是找了到二逼的区间线段数+权值平衡树做做,没想到做了4个多小时。。。。但终于学会了写树套树的正确姿势
#include<cstdio>
#define N 200100
#define M 2333333
#define inf 1e8
int n,m,p,l,r,k,pos,tot,tmp,ans,top,L,R,mid,a[N],father[M],son[M][2],size[M],val[M];
struct tree{int l,r,root;}t[N];
void pushup(int x){if(x)size[x]=size[son[x][0]]+size[son[x][1]]+1;}
int leftmin(int x){if(!son[x][0])return x;return leftmin(son[x][0]);}
void newnode(int &x,int fa,int da){
if(top)x=top,top=0;else x=++tot;
father[x]=fa;
son[x][0]=son[x][1]=0;
val[x]=da;
size[x]=1;
}
void rotate(int x,int k){
int y=father[x];
son[y][!k]=son[x][k];
father[son[y][!k]]=y;
son[father[y]][son[father[y]][1]==y]=x;
father[x]=father[y];
son[x][k]=y;
father[y]=x;
pushup(y);
}
void splay(int x,int goal,int &root){
while(father[x]!=goal){
int y=father[x],z=father[y],f=(son[z][0]==y);
if(z==goal)rotate(x,son[y][0]==x);else{
if(son[y][f]==x)rotate(x,!f);else rotate(y,f);
rotate(x,f);
}
}
pushup(x);
if(!goal)root=x;
}
void kthfind(int x,int key){
if(!x)return;
if(key<=val[x])kthfind(son[x][0],key);else{
tmp+=size[son[x][0]]+1;
kthfind(son[x][1],key);
}
}
int findit(int x,int key){
if(key<val[x])return findit(son[x][0],key);
if(key==val[x])return x;
return findit(son[x][1],key);
}
void insert(int &root,int key){
int x=root;
if(!root){newnode(root,0,key);return;}
while(son[x][key>val[x]])size[x]++,x=son[x][key>val[x]];
size[x]++;
newnode(son[x][key>val[x]],x,key);
splay(son[x][key>val[x]],0,root);
}
void del(int &root,int key){
int x=findit(root,key);
splay(x,0,root);
top=root;
if(!son[x][1]){
father[son[x][0]]=0;
root=son[x][0];
}else{
splay(leftmin(son[x][1]),root,root);
son[son[root][1]][0]=son[root][0];
father[son[root][1]]=0;
father[son[root][0]]=son[root][1];
root=son[root][1];
}
pushup(root);
}
void pre(int x,int key){
if(!x)return;
if(val[x]<key){if(val[x]>ans)ans=val[x];pre(son[x][1],key);}
else pre(son[x][0],key);
}
void suc(int x,int key){
if(!x)return;
if(val[x]>key){if(val[x]<ans)ans=val[x];suc(son[x][0],key);}
else suc(son[x][1],key);
}
void change(int k,int x,int key,int last){
del(t[k].root,last);
insert(t[k].root,key);
int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
if(l==r)return;
if(x<=mid)change(k<<1,x,key,last);else change(k<<1|1,x,key,last);
}
void getk(int k,int x,int y,int key){
int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
if(x==l&&r==y)kthfind(t[k].root,key);
else{
if(x>mid)getk(k<<1|1,x,y,key);
else if(y<=mid)getk(k<<1,x,y,key);
else {getk(k<<1,x,mid,key);getk(k<<1|1,mid+1,y,key);}
}
}
void getpre(int k,int x,int y,int key){
int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
if(x==l&&r==y)pre(t[k].root,key);else{
if(x>mid)getpre(k<<1|1,x,y,key);
else if(y<=mid)getpre(k<<1,x,y,key);
else getpre(k<<1,x,mid,key),getpre(k<<1|1,mid+1,y,key);
}
}
void getsuc(int k,int x,int y,int key){
int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
if(x==l&&r==y)suc(t[k].root,key);else{
if(x>mid)getsuc(k<<1|1,x,y,key);
else if(y<=mid)getsuc(k<<1,x,y,key);
else getsuc(k<<1,x,mid,key),getsuc(k<<1|1,mid+1,y,key);
}
}
void buildtree(int k,int l,int r){
t[k].l=l;t[k].r=r;char ch;
for(int i=l;i<=r;i++)insert(t[k].root,a[i]);
if(l==r)return;
int mid=(l+r)>>1;
buildtree(k<<1,l,mid);
buildtree(k<<1|1,mid+1,r);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
buildtree(1,1,n);
while(m--){
scanf("%d",&p);
if(p!=3){
scanf("%d%d%d",&l,&r,&k);
if(p==1){
tmp=1;getk(1,l,r,k);
printf("%d\n",tmp);
}else if(p==2){
L=0;R=1e8;
while(L<=R){
mid=(L+R)>>1;
tmp=1;getk(1,l,r,mid);
if(tmp<=k)L=mid+1,ans=mid;else R=mid-1;
}
printf("%d\n",ans);
}else if(p==4){
ans=-inf;
getpre(1,l,r,k);
printf("%d\n",ans);
}else if(p==5){
ans=inf;
getsuc(1,l,r,k);
printf("%d\n",ans);
}
}else{
scanf("%d%d",&pos,&k);
change(1,pos,k,a[pos]);
a[pos]=k;
}
}
}
待做:BZOJ4009
评论 (0)