线段树套平衡树

累死了,终于过了

其实也没有什么好说的,就是内层平衡树用struct包起来,外层线段树乱搞即可

唯一要注意的是求区间第k大时要二分答案,边界不能写错,详见代码

由于我太菜了,这题调了很久,不想写题解了,给个链接

#include<bits/stdc++.h>
using namespace std;  
int n,m,root,minn,maxx;
int cnt,cur,ans,MX;
int ls[1010101],rs[1010101],a[50010];
struct hh  
{  
    int v,sz,lson,rson;  
}tr[101010<<7];
struct zyf_tree
{
    int root;
    bool leaf(int x){return !(tr[x].lson||tr[x].rson);}  
    void new_tr(int &k,int x)  
    {  
        k=++cnt;  
        tr[k].v=x;  
        tr[k].sz=1;  
    }  
    void push_up(int x)  
    {  
        if (leaf(x)) return;  
        tr[x].v=max(tr[tr[x].lson].v,tr[tr[x].rson].v);  
        tr[x].sz=tr[tr[x].lson].sz+tr[tr[x].rson].sz;  
    }  
    void rotate(int k,bool dir)   
    {  
        if (!dir)  
        {  
            int r=tr[k].rson;  
            tr[k].rson=tr[k].lson;  
            tr[k].lson=tr[tr[k].rson].lson;  
            tr[tr[k].rson].lson=tr[tr[k].rson].rson;  
            tr[tr[k].rson].rson=r;  
            push_up(tr[k].lson);  
            push_up(tr[k].rson);  
        }  
        else  
        {  
            int l=tr[k].lson;  
            tr[k].lson=tr[k].rson;  
            tr[k].rson=tr[tr[k].lson].rson;  
            tr[tr[k].lson].rson=tr[tr[k].lson].lson;  
            tr[tr[k].lson].lson=l;  
            push_up(tr[k].lson);  
            push_up(tr[k].rson);  
        }  
    }  
    void maintain(int k)  
    {  
        if (leaf(k)) return;
        if (tr[tr[k].lson].sz>=tr[tr[k].rson].sz*4) rotate(k,0);
        if (tr[tr[k].rson].sz>=tr[tr[k].lson].sz*4) rotate(k,1);
    }  
    void insert(int &k,int x)  
    {  
        if (!k)   
        {  
            new_tr(k,x);
            return;  
        }  
        if (leaf(k))   
        {  
            new_tr(tr[k].lson,min(x,tr[k].v));   
            new_tr(tr[k].rson,max(x,tr[k].v));
        	push_up(k);
        	return;  
    	}  
    	int l=tr[tr[k].lson].v;
    	if (x>l) insert(tr[k].rson,x);
    	else insert(tr[k].lson,x);
    	maintain(k);
    	push_up(k);
    }  
    void del(int &k,int fa,int x)
    {  
    	if (leaf(k))
    	{  
    	    if (!fa)
    	    {
    	    	k=0;
    	    	return;
    	    }
            if (tr[k].v==x)
        	{  
        	    if (tr[fa].lson==k) tr[fa]=tr[tr[fa].rson];
        	    else tr[fa]=tr[tr[fa].lson];
        	}
        	return;  
    	}  
    	int l=tr[tr[k].lson].v;
    	if (x>l) del(tr[k].rson,k,x);
    	else del(tr[k].lson,k,x);
    	maintain(k);
    	push_up(k);
    }  
    int rnk(int k,int x)  
    {  
        if (leaf(k))
    	{  
    	    if (x>tr[k].v) return 1;
    	    return 0;
    	}  
    	int l=tr[tr[k].lson].v;
    	if (x>l) return rnk(tr[k].rson,x)+tr[tr[k].lson].sz;
    	return rnk(tr[k].lson,x);
    }  
    int kth(int k,int rnk)
    {  
        if (leaf(k)) return tr[k].v;
        if (rnk<=tr[tr[k].lson].sz) return kth(tr[k].lson,rnk);
        return kth(tr[k].rson,rnk-tr[tr[k].lson].sz);
    }
    int pre(int k,int x)
    {
        int ret=INT_MIN+1;
		while (tr[k].v>=x)
        {
            if (leaf(k)) return ret;
            if (tr[tr[k].lson].v<x)
			{
				ret=max(ret,tr[tr[k].lson].v);
				k=tr[k].rson;
			}
			else k=tr[k].lson;
        }
        if (tr[k].v<x) ret=max(ret,tr[k].v);
        return ret;
    }
    int scc(int k,int x)
    {
        int ret=INT_MAX;
        while (k)
        {
            if (tr[k].v>x) ret=min(ret,tr[k].v);
            if (tr[tr[k].lson].v>x)
            {
                ret=min(ret,tr[tr[k].lson].v);
                k=tr[k].lson;
            }
            else k=tr[k].rson;
        }
        return ret;
    }
}zyf[1010101];
void insert(int &k,int l,int r,int pos,int x)
{
    if (!k) k=++cur;
    zyf[k].insert(zyf[k].root,x);
    if (l==r) return;
    int mid=(l+r)>>1;
    if (pos<=mid) insert(ls[k],l,mid,pos,x);
    else insert(rs[k],mid+1,r,pos,x);
}
void modify(int k,int l,int r,int pos,int x)
{
    if (!k) return;
    zyf[k].del(zyf[k].root,0,a[pos]);
    zyf[k].insert(zyf[k].root,x);
    if (l==r) return;
    int mid=(l+r)>>1;
    if (pos<=mid) modify(ls[k],l,mid,pos,x);
    else modify(rs[k],mid+1,r,pos,x);
}
void rnk(int k,int l,int r,int x,int y,int woc)
{
    if (!k) return;
    if (x<=l&&r<=y) 
    {
        ans+=zyf[k].rnk(zyf[k].root,woc);
        return;
    }
    int mid=(l+r)>>1;
    if (x<=mid) rnk(ls[k],l,mid,x,y,woc);
    if (y>mid) rnk(rs[k],mid+1,r,x,y,woc);
}
int kth(int k,int x,int y)
{
    int l=INT_MIN,r=MX+1,ret=0;
    while (l<r)
    {
        int mid=(l+r)>>1;
        ans=0;
        rnk(root,1,n,x,y,mid);
        if (ans<k) l=mid+1,ret=mid;
        else r=mid;
    }
    return ret;
}
void get_pre(int k,int l,int r,int x,int y,int woc)
{
    if (!k) return;
    if (x<=l&&r<=y)
    {
        ans=max(ans,zyf[k].pre(zyf[k].root,woc));
        return;
    }
    int mid=(l+r)>>1;
    if (x<=mid) get_pre(ls[k],l,mid,x,y,woc);
    if (y>mid) get_pre(rs[k],mid+1,r,x,y,woc);
}
void get_scc(int k,int l,int r,int x,int y,int woc)
{
    if (!k) return;
    if (x<=l&&r<=y)
    {
        ans=min(ans,zyf[k].scc(zyf[k].root,woc));
        return;
    }
    int mid=(l+r)>>1;
    if (x<=mid) get_scc(ls[k],l,mid,x,y,woc);
    if (y>mid) get_scc(rs[k],mid+1,r,x,y,woc);
}
int main()  
{  
    int cur=0,anss;
	scanf("%d %d",&n,&m);  
    for (int i=1;i<=n;i++) scanf("%d",&a[i]),insert(root,1,n,i,a[i]),MX=max(MX,a[i]);
    for (int i=1;i<=m;i++)
    {
    	int l,r,x,opt;
    	scanf("%d",&opt);
    	if (opt==1)
    	{
    		scanf("%d %d %d",&l,&r,&x);
    		ans=0;
    		rnk(root,1,n,l,r,x);
    		ans++;
    		printf("%d\n",ans);
    	}
    	if (opt==2)
    	{
    		scanf("%d %d %d",&l,&r,&x);
    		anss=kth(x,l,r);
    		printf("%d\n",anss);
    	}
    	if (opt==3)
    	{
    		scanf("%d %d",&l,&x);
    		modify(root,1,n,l,x);
    		a[l]=x;
    		MX=max(MX,x);
    	}
    	if (opt==4)
    	{
    		scanf("%d %d %d",&l,&r,&x);
    		ans=INT_MIN+1;
    		get_pre(root,1,n,l,r,x);
    		printf("%d\n",ans);
    	}
    	if (opt==5)
    	{
    		scanf("%d %d %d",&l,&r,&x);
    		ans=INT_MAX;
    		get_scc(root,1,n,l,r,x);
    		printf("%d\n",ans);
    	}
    }
}

注:内层是zyf树,想学的可以看另一篇博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值