树套树
P3380 【模板】树套树
这里采取的是线段树套平衡树(FHQ)
考虑树套树可以解决类似于在两维区间限制类似操作的问题
把线段树上每个节点维护一颗平衡树,维护的方法也非常简单,发现只要知道root,就能够访问平衡树,非常简单
考虑每个节点会被添加log次,所以平衡树要 nlogn 个节点,线段树普通 4n 个节点
考虑二操作,就二分一下排名的数,查排名,\(log^3\)
修改操作,把所有包含修改节点的平衡树进行修改
注意!!!!!!!(血淋淋的教训,我调了好几个小时)
平衡树添加节点一定要按照顺序合并,即先按照排名分裂,在依次合并,保证满足二叉树性质,这个在添加节点和修改节点时都要满足
查排名是查有多少个小于x的数,因为我们答案最终是要累加起来,别忘了最后+1
修改节点时一定要把修改出来的节点,所有的变量都初始化!!!
#include<bits/stdc++.h>
#define ls(x) dt[x].ls
#define rs(x) dt[x].rs
#define pri(x) dt[x].pri
#define key(x) dt[x].key
#define siz(x) dt[x].siz
using namespace std;
const int N=5e4+5,M=1e8;
int cnt,n,m;
int a[N];
struct node{
int root,key;
}tr[N*4];
struct dot{
int ls,rs,pri,key,siz;
}dt[N*20];
struct FHQ{
int newnode(int x){
dt[++cnt]={0,0,rand(),x,1};
return cnt;
}
void update(int u){
siz(u)=siz(ls(u))+siz(rs(u))+1;
}
void split(int u,int x,int &L,int &R){
if(u==0){
L=R=0;
return;
}
if(key(u)<=x){
L=u;
split(rs(u),x,rs(u),R);
}
else{
R=u;
split(ls(u),x,L,ls(u));
}
update(u);
}
int merge(int L,int R){
if(!L||!R) return L+R;
if(pri(L)<pri(R)){
rs(L)=merge(rs(L),R);
update(L);
return L;
}
else{
ls(R)=merge(L,ls(R));
update(R);
return R;
}
}
void insert(int &root,int l,int r){//RE表明没写返回值
for(int i=l;i<=r;i++){
int L,R;
split(root,a[i],L,R);
root=merge(L,merge(newnode(a[i]),R));
}
}
int rank(int &root,int x){
int L,R;
split(root,x-1,L,R);
int res=siz(L);//这里要判断是否已经全满了
root=merge(L,R);
return res;
}
int find(int u,int k){
if(!u) return -1;
if(siz(ls(u))+1==k) return key(u);
else if(siz(ls(u))+1<k) return find(rs(u),k-siz(ls(u))-1);
else return find(ls(u),k);
}
void change(int &root,int x,int k){
int L,R,p=0;
split(root,x-1,L,R);
split(R,x,p,R);
int g=p;
p=merge(ls(p),rs(p));
root=merge(L,merge(p,R));//插入一定是要有顺序的
split(root,k,L,R);
if(g){
dt[g]={0,0,rand(),k,1};//一定要全部修改
root=merge(L,merge(g,R));
}
}
int pre(int &root,int x){
int L,R;
split(root,x-1,L,R);
int res=find(L,siz(L));
if(res==-1) res=-2147483647;
root=merge(L,R);
return res;
}
int suc(int &root,int x){
int L,R;
split(root,x,L,R);
int res=find(R,1);
if(res==-1) res=2147483647;
root=merge(L,R);
return res;
}
void print(int u){
if(!u) return;
print(ls(u));
printf("%d ",key(u));
print(rs(u));
}
}FHQ;
struct tree{
void build(int k,int l,int r){
FHQ.insert(tr[k].root,l,r);
if(l==r){
tr[k].key=a[l];
return;
}
int mid=(l+r)>>1;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
}
void change(int k,int l,int r,int x,int g){
FHQ.change(tr[k].root,a[x],g);
if(l==r){
return;
}
int mid=(l+r)>>1;
if(x<=mid) change(k*2,l,mid,x,g);
else change(k*2+1,mid+1,r,x,g);
}
void she(int &res,int op){
if(op==1) res=0;
if(op==2) res=-2147483647;
if(op==3) res=2147483647;
}
void update(int &res,int op,int num){
if(op==1) res+=num;
if(op==2) res=max(res,num);
if(op==3) res=min(res,num);
}
int figue(int k,int g,int op){
if(op==1) return FHQ.rank(tr[k].root,g);
if(op==2) return FHQ.pre(tr[k].root,g);
if(op==3) return FHQ.suc(tr[k].root,g);
}
int query(int k,int l,int r,int x,int y,int g,int op){
if(x<=l&&r<=y){
return figue(k,g,op);
}
int mid=(l+r)>>1,res;
she(res,op);
if(x<=mid) update(res,op,query(k*2,l,mid,x,y,g,op));
if(y>mid) update(res,op,query(k*2+1,mid+1,r,x,y,g,op));
return res;
}
int middle(int x,int y,int k){
int l=0,r=M;
while(l<r){
int mid=(l+r+1)>>1;
if(query(1,1,n,x,y,mid,1)+1<=k) l=mid;
else r=mid-1;
}
return l;
}
}tree;
int main(){
srand(time(NULL));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
tree.build(1,1,n);
for(int i=1;i<=m;i++){
int op,l,r,k;
scanf("%d%d%d",&op,&l,&r);
if(op==1){
scanf("%d",&k);
printf("%d\n",tree.query(1,1,n,l,r,k,1)+1);
}
if(op==2){
scanf("%d",&k);
printf("%d\n",tree.middle(l,r,k));
}
if(op==3){
tree.change(1,1,n,l,r);
a[l]=r;
}
if(op==4){
scanf("%d",&k);
printf("%d\n",tree.query(1,1,n,l,r,k,2));
}
if(op==5){
scanf("%d",&k);
printf("%d\n",tree.query(1,1,n,l,r,k,3));
}
}
return 0;
}

浙公网安备 33010602011771号