P3380 【模板】二逼平衡树(树套树)
一天写一题,一题写一天
看了看题解,这道题的做法太太太多了
有整体二分,cdq,分块,树套树还有乱搞?
整体二分,cdq我不会,就不谈了
先说分块:时间复杂度n1.5log2,容易被卡(虽然这道题没有被卡)
树套树(下标线段树+权值平衡树):时间复杂度:nlog3
树套树(权值线段树+下标平衡树):时间复杂度:nlog2
因为是第一次写树套树的题目,用了非常久的时间
所谓树套树(就该题而言),就是在每一个线段树的节点中建一颗平衡树,然后维护每一个节点对应的平衡树。
具体建树方式如下图:
修改:修改一个区间上的一个点。需要修改修改线段树的一条链所对应的平衡树,要先插入后删除,最后还要修改原数组
建树:建树是按照下标线段树建立的,对于与一个下标,要往平衡树插入对应区间内的所有值
查询:除了第k大的查询都比较相似,就说一下第k大的查询
这个查询是采取的二分形式,二分查询的值,时间复杂度来源于二分+线段树查询+平衡树查询都是log级的,所以时间复杂度log3
#include <bits/stdc++.h>
#define inf 0x7fffffff
//#define ll long long
//#define int long long
//#define double long double
//#define double long long
#define re int
//#define void inline void
#define eps 1e-8
//#define mod 1e9+7
//#define ls(p) p<<1
//#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define mk make_pair
#define P pair < int , int >
using namespace std;
const int mod=1e9+7;
//const int inf=1e18;
const int M=1e8;
const int N=5e4+5;//??????.???? 4e8
struct fhq
{
int l,r,sz,val,key;
}e[N*50];
int tot;
int newnode(int val)
{
e[++tot].val=val;
e[tot].key=rand();
e[tot].sz=1;
return tot;
}
void update(int p)
{
e[p].sz=e[e[p].l].sz+e[e[p].r].sz+1;
}
void split(int p,int val,int &x,int &y)
{
if(!p) x=y=0;
else
{
if(e[p].val<=val)
{
x=p;
split(e[p].r,val,e[x].r,y);//
update(x);
}
else
{
y=p;
split(e[p].l,val,x,e[y].l);//
update(y);
}
// update(p);
}
}
void merge(int &p,int x,int y)
{
if(!x||!y)
{
p=x+y;
return;
}
if(e[x].key<e[y].key)
{
p=x;//
merge(e[p].r,e[x].r,y);//
// update(x);
}
else
{
p=y;//
merge(e[p].l,x,e[y].l);//
// update(y);
}
update(p);//这里要注意
}
void insert(int &p,int val)
{
int x,y;
split(p,val-1,x,y);
merge(p,x,newnode(val));
merge(p,p,y);
}
void remove(int &p,int val)
{
int x,y,z,w;
split(p,val-1,x,y);
split(y,val,z,w);
merge(z,e[z].l,e[z].r);
merge(z,z,w);
merge(p,x,z);
}
int getrank(int &p,int val)
{
int x,y;
split(p,val-1,x,y);
int ans=e[x].sz;
merge(p,x,y);
return ans;
}
int last(int p,int val)
{
int ans=INT_MIN+1;
while(p)
{
if(val>e[p].val)
{
ans=max(ans,e[p].val);
p=e[p].r;
}
else p=e[p].l;
}
return ans;
}
int next(int p,int val)
{
int ans=INT_MAX;
while(p)
{
if(val<e[p].val)
{
ans=min(ans,e[p].val);
p=e[p].l;
}
else p=e[p].r;
}
return ans;
}
int kth(int p,int rank)
{
while(p)
{
if(rank<e[e[p].l].sz) p=e[p].l;
else if(rank>=e[e[p].l].sz+1)
{
rank-=e[e[p].l].sz+1;
p=e[p].r;
}
else return e[p].val;
}
return 0;
}
struct tree
{
int l,r,lc,rc;
int rt;
}t[N*4];
int root;
int cnt;
int a[N];
void bulid(int &p,int l,int r)
{
p=++cnt;
t[p].l=l,t[p].r=r;
for(re i=l;i<=r;i++) insert(t[p].rt,a[i]);
if(l==r) return;
int mid=(l+r)>>1;
bulid(t[p].lc,l,mid);bulid(t[p].rc,mid+1,r);
}
void change(int p,int pos,int val)
{
insert(t[p].rt,val);
remove(t[p].rt,a[pos]);
if(t[p].l==t[p].r) return;
int mid=(t[p].l+t[p].r)>>1;
if(pos<=mid) change(t[p].lc,pos,val);
else change(t[p].rc,pos,val);
}
int qrank(int p,int l,int r,int val)
{
if(t[p].l==l&&t[p].r==r) return getrank(t[p].rt,val);
int mid=(t[p].l+t[p].r)>>1;
if(r<=mid) return qrank(t[p].lc,l,r,val);
else if(l>=mid+1) return qrank(t[p].rc,l,r,val);
return qrank(t[p].lc,l,mid,val)+qrank(t[p].rc,mid+1,r,val);
}
int qlast(int p,int l,int r,int val)
{
if(t[p].l==l&&t[p].r==r) return last(t[p].rt,val);
int mid=(t[p].l+t[p].r)>>1;
if(r<=mid) return qlast(t[p].lc,l,r,val);
else if(l>=mid+1) return qlast(t[p].rc,l,r,val);
return max(qlast(t[p].lc,l,mid,val),qlast(t[p].rc,mid+1,r,val));
}
int qnext(int p,int l,int r,int val)
{
if(t[p].l==l&&t[p].r==r) return next(t[p].rt,val);
int mid=(t[p].l+t[p].r)>>1;
if(r<=mid) return qnext(t[p].lc,l,r,val);
else if(l>=mid+1) return qnext(t[p].rc,l,r,val);
return min(qnext(t[p].lc,l,mid,val),qnext(t[p].rc,mid+1,r,val));
}
int qkth(int p,int l,int r,int rank)
{
int ll=0,rr=1e8;
while(rr-ll>1)
{
int mid=(ll+rr)>>1;
if(qrank(root,l,r,mid)<rank) ll=mid;
else rr=mid;
}
if(qrank(root,l,r,rr)<rank) return rr;
else return ll;
}
int n,q;
void solve()
{
cin>>n>>q;
for(re i=1;i<=n;i++) scanf("%d",&a[i]);
bulid(root,1,n);
while(q--)
{
int op,l,r,pos,x;
scanf("%d",&op);
if(op==3)
{
scanf("%d%d",&pos,&x);
change(root,pos,x);
a[pos]=x;
}
else
{
scanf("%d%d%d",&l,&r,&x);
if(op==1) printf("%d\n",qrank(root,l,r,x)+1);
if(op==2) printf("%d\n",qkth(root,l,r,x));
if(op==4) printf("%d\n",qlast(root,l,r,x));
if(op==5) printf("%d\n",qnext(root,l,r,x));
}
}
}
signed main()
{
int T=1;
// cin>>T;
for(int index=1;index<=T;index++)
{
solve();
// puts("");
}
return 0;
}
/*
*/