P3380-二逼平衡树
P3380 【模板】二逼平衡树(树套树)
模版:
#include <bits/stdc++.h>
using namespace std;
const int maxn=5e4+10;
const ll inf=1e16;
const int maxm=5e5+10;
const ld eps=1e-12;
int n,m;
//-------shuru
int yuan[maxn],lisan[maxn<<2],totshu;
struct xunwen{
int zhong,lo,ro,kth;
}allq[maxn];
//-------
//-----zhuxishu
struct node{
int lo;int ro;int zhi;
}all[maxn*80];
int rt[maxn],tot;
void pushup(int now,int lo,int ro){all[now].zhi=all[lo].zhi+all[ro].zhi;}
void build(int &now,int lo,int ro){
now=++tot;
if(lo==ro) return;
int mid=(lo+ro)>>1;
build(all[now].lo,lo,mid);
build(all[now].ro,mid+1,ro);
}
void inser(int &now,int rnow,int lo,int ro,int pos,int zhi){
now=++tot;all[now]=all[rnow];
if(lo==ro){all[now].zhi+=zhi;return;}
int mid=(lo+ro)>>1;
if(pos<=mid) inser(all[now].lo,all[rnow].lo,lo,mid,pos,zhi);
else inser(all[now].ro,all[rnow].ro,mid+1,ro,pos,zhi);
pushup(now,all[now].lo,all[now].ro);
}
//------------
//-----------shuzhuagshuzu
int s[maxn];
inline int lowbit(int x){return x&(-x);}
//------------
//----------shutaoshu
int totx,toty;
int xbi[510],ybi[510];
ll reqkth(int wlo,int wro,int lo1,int ro1,int lo,int ro,int kth){
if(lo==ro) return lo;
int mid=(lo+ro)>>1;
int sum=0;
for(int i=1;i<=totx;i++) sum-=all[all[xbi[i]].lo].zhi;
for(int i=1;i<=toty;i++) sum+=all[all[ybi[i]].lo].zhi;
sum+=(all[all[ro1].lo].zhi-all[all[lo1].lo].zhi);//
if(sum>=kth){
for(int i=1;i<=totx;i++) xbi[i]=all[xbi[i]].lo;
for(int i=1;i<=toty;i++) ybi[i]=all[ybi[i]].lo;
return reqkth(wlo,wro,all[lo1].lo,all[ro1].lo,lo,mid,kth);//
}
else{
for(int i=1;i<=totx;i++) xbi[i]=all[xbi[i]].ro;
for(int i=1;i<=toty;i++) ybi[i]=all[ybi[i]].ro;
return reqkth(wlo,wro,all[lo1].ro,all[ro1].ro,mid+1,ro,kth-sum);
}
}
ll reqrk(int wlo,int wro,int lo1,int ro1,int lo,int ro,int pos){
if(lo==ro) return 0;
int mid=(lo+ro)>>1;
debug4(lo,ro,pos,mid)
if(pos<=mid){
for(int i=1;i<=totx;i++) xbi[i]=all[xbi[i]].lo;
for(int i=1;i<=toty;i++) ybi[i]=all[ybi[i]].lo;
return reqrk(wlo,wro,all[lo1].lo,all[ro1].lo,lo,mid,pos);
}
else{
int sum=0;
for(int i=1;i<=totx;i++) sum-=all[all[xbi[i]].lo].zhi;
for(int i=1;i<=toty;i++) sum+=all[all[ybi[i]].lo].zhi;
sum+=(all[all[ro1].lo].zhi-all[all[lo1].lo].zhi);
for(int i=1;i<=totx;i++) xbi[i]=all[xbi[i]].lo;
for(int i=1;i<=toty;i++) ybi[i]=all[ybi[i]].lo;
return reqrk(wlo,wro,all[lo1].ro,all[ro1].ro,mid+1,ro,pos)+sum;
}
}
ll findpre(int wlo,int wro,int lo1,int ro1,int lo,int ro,int pos){
if(lo==ro) return lo;
int mid=(lo+ro)>>1;
if(pos<=mid){
int sum=0;
for(int i=wlo;i;i-=lowbit(i)) sum-=all[all[xbi[i]].lo].zhi;
for(int i=wro;i;i-=lowbit(i)) sum+=all[all[ybi[i]].lo].zhi;
sum+=(all[all[ro1].lo].zhi-all[all[lo1].lo].zhi);//
if(sum==0) return -1;////
for(int i=wlo;i;i-=lowbit(i)) xbi[i]=all[xbi[i]].lo;
for(int i=wro;i;i-=lowbit(i)) ybi[i]=all[ybi[i]].lo;
return findpre(wlo,wro,all[lo1].lo,all[ro1].lo,lo,mid,pos);
}
else{
int sum=0;
for(int i=wlo;i;i-=lowbit(i)) sum-=all[all[xbi[i]].ro].zhi;
for(int i=wro;i;i-=lowbit(i)) sum+=all[all[ybi[i]].ro].zhi;
sum+=all[all[ro1].ro].zhi;
sum-=all[all[lo1].ro].zhi;
int xbii[510],ybii[510];
for(int i=wlo;i;i-=lowbit(i)) xbii[i]=xbi[i],xbi[i]=all[xbi[i]].ro;
for(int i=wro;i;i-=lowbit(i)) ybii[i]=ybi[i],ybi[i]=all[ybi[i]].ro;
if(sum) sum=findpre(wlo,wro,all[lo1].ro,all[ro1].ro,mid+1,ro,pos);
else sum=-1;
if(sum!=-1) return sum;////
sum=0;
for(int i=wlo;i;i-=lowbit(i)) sum-=all[all[xbii[i]].lo].zhi;
for(int i=wro;i;i-=lowbit(i)) sum+=all[all[ybii[i]].lo].zhi;
sum+=all[all[ro1].lo].zhi;
sum-=all[all[lo1].lo].zhi;
for(int i=wlo;i;i-=lowbit(i)) xbi[i]=all[xbii[i]].lo;
for(int i=wro;i;i-=lowbit(i)) ybi[i]=all[ybii[i]].lo;
if(sum) return findpre(wlo,wro,all[lo1].lo,all[ro1].lo,lo,mid,pos);
else return -1;
}
}
ll findhou(int wlo,int wro,int lo1,int ro1,int lo,int ro,int pos){
if(lo==ro) return lo;
int mid=(lo+ro)>>1;
if(pos<=mid){
int sum=0;
for(int i=wlo;i;i-=lowbit(i)) sum-=all[all[xbi[i]].lo].zhi;
for(int i=wro;i;i-=lowbit(i)) sum+=all[all[ybi[i]].lo].zhi;
sum+=(all[all[ro1].lo].zhi-all[all[lo1].lo].zhi);
int xbii[510],ybii[510];
for(int i=wlo;i;i-=lowbit(i)) xbii[i]=xbi[i],xbi[i]=all[xbi[i]].lo;
for(int i=wro;i;i-=lowbit(i)) ybii[i]=ybi[i],ybi[i]=all[ybi[i]].lo;
if(sum) sum=findhou(wlo,wro,all[lo1].lo,all[ro1].lo,lo,mid,pos);
else sum=-1;
if(sum!=-1) return sum;
sum=0;
for(int i=wlo;i;i-=lowbit(i)) sum-=all[all[xbii[i]].ro].zhi;
for(int i=wro;i;i-=lowbit(i)) sum+=all[all[ybii[i]].ro].zhi;
sum+=all[all[ro1].ro].zhi;
sum-=all[all[lo1].ro].zhi;
for(int i=wlo;i;i-=lowbit(i)) xbi[i]=all[xbii[i]].ro;
for(int i=wro;i;i-=lowbit(i)) ybi[i]=all[ybii[i]].ro;
if(sum) return findhou(wlo,wro,all[lo1].ro,all[ro1].ro,mid+1,ro,pos);
else return -1;
}
else{
int sum=0;
for(int i=wlo;i;i-=lowbit(i)) sum-=all[all[xbi[i]].ro].zhi;
for(int i=wro;i;i-=lowbit(i)) sum+=all[all[ybi[i]].ro].zhi;
sum+=(all[all[ro1].ro].zhi-all[all[lo1].ro].zhi);
if(sum==0) return -1;
for(int i=wlo;i;i-=lowbit(i)) xbi[i]=all[xbi[i]].ro;
for(int i=wro;i;i-=lowbit(i)) ybi[i]=all[ybi[i]].ro;
return findhou(wlo,wro,all[lo1].ro,all[ro1].ro,mid+1,ro,pos);
}
}
void add(int pos,int zhi,int val){
for(int i=pos;i<=n;i+=lowbit(i)) inser(s[i],s[i],1,totshu,zhi,val);//totshu
}
//------------------
signed main(){
ios;fre();
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>yuan[i];lisan[i]=yuan[i];
}
totshu=n;////
for(int i=1;i<=m;i++){
cin>>allq[i].zhong;
if(allq[i].zhong==3) cin>>allq[i].lo>>allq[i].ro,lisan[++totshu]=allq[i].ro;//pos->lo,zhi->ro,modify
else if(allq[i].zhong==2) cin>>allq[i].lo>>allq[i].ro>>allq[i].kth;
else{
cin>>allq[i].lo>>allq[i].ro>>allq[i].kth;
lisan[++totshu]=allq[i].kth;//chaxunmoushu k
}
}
sort(lisan+1,lisan+1+totshu);
totshu=unique(lisan+1,lisan+1+totshu)-lisan-1;
build(rt[0],1,totshu);
for(int i=1;i<=n;i++){
int now1=lower_bound(lisan+1,lisan+1+totshu,yuan[i])-lisan;
yuan[i]=now1;
inser(rt[i],rt[i-1],1,totshu,now1,1);
}
for(int i=1;i<=n;i++) s[i]=rt[0];////
/*------------debug
totx=toty=0;
for(int j=0;j;j-=lowbit(j)) xbi[++totx]=s[j];
for(int j=4;j;j-=lowbit(j)) ybi[++toty]=s[j];
int nowk1=lower_bound(lisan+1,lisan+1+totshu,1)-lisan;
int nowk=reqrk(0,4,rt[0],rt[4],1,totshu,nowk1)+1;
debug1(nowk)
-------------*/
for(int i=1;i<=m;i++){
if(allq[i].zhong==1){
int now1=lower_bound(lisan+1,lisan+1+totshu,allq[i].kth)-lisan;
int lo=allq[i].lo-1,ro=allq[i].ro;
totx=toty=0;
for(int j=lo;j;j-=lowbit(j)) xbi[++totx]=s[j];
for(int j=ro;j;j-=lowbit(j)) ybi[++toty]=s[j];
int now2=reqrk(lo,ro,rt[lo],rt[ro],1,totshu,now1)+1;////congxiaodaoda+1
cout<<now2<<endl;
}
else if(allq[i].zhong==2){
int lo=allq[i].lo-1,ro=allq[i].ro;
debug2(lo,ro)
totx=toty=0;
for(int j=lo;j;j-=lowbit(j)) xbi[++totx]=s[j];
for(int j=ro;j;j-=lowbit(j)) ybi[++toty]=s[j];
int now2=reqkth(lo,ro,rt[lo],rt[ro],1,totshu,allq[i].kth);//congxiaodaoda
cout<<lisan[now2]<<endl;
}
else if(allq[i].zhong==3){
add(allq[i].lo,yuan[allq[i].lo],-1);
yuan[allq[i].lo]=lower_bound(lisan+1,lisan+1+totshu,allq[i].ro)-lisan;
add(allq[i].lo,yuan[allq[i].lo],1);
}
else if(allq[i].zhong==4){
int now1=lower_bound(lisan+1,lisan+1+totshu,allq[i].kth)-lisan-1;//kth's qianqu
int lo=allq[i].lo-1,ro=allq[i].ro;
for(int j=lo;j;j-=lowbit(j)) xbi[j]=s[j];
for(int j=ro;j;j-=lowbit(j)) ybi[j]=s[j];
now1=findpre(lo,ro,rt[lo],rt[ro],1,totshu,now1);
if(now1==-1) cout<<-2147483647<<endl;
else cout<<lisan[now1]<<endl;
}
else{
int now1=lower_bound(lisan+1,lisan+1+totshu,allq[i].kth)-lisan+1;
int lo=allq[i].lo-1,ro=allq[i].ro;
for(int j=lo;j;j-=lowbit(j)) xbi[j]=s[j];
for(int j=ro;j;j-=lowbit(j)) ybi[j]=s[j];
now1=findhou(lo,ro,rt[lo],rt[ro],1,totshu,now1);
if(now1==-1) cout<<2147483647<<endl;
else cout<<lisan[now1]<<endl;
}
}
return 0;
}
- 代码比较丑,为了优化\(ydii[i],xdii[i],xdi[i],ydi[i]\)数组的空间,记录进数组的时候改了一点写法,但有些部分还没改。
- 使用的是树状数组套主席树,常数不是很大。洛谷跑了\(1.28s\).
- 注意这里的排名\(kth\)是从小到大的排名,查询完\(rk\)之后要加\(1\)(\(reqrk\)函数实际上查询的是比当前数小的数有多少个)
- 树套树支持动态的区间\(rk/kth\)查询,查询某个数的区间前驱和后继。

浙公网安备 33010602011771号