• [Lugu3380]【模板】二逼平衡树(树套树)


    题面戳我
    您需要写一种数据结构来维护一个有序数列,其中需要提供以下操作:
    1、查询k在区间内的排名
    2、查询区间内排名为k的值
    3、修改某一位值上的数值
    4、查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)
    5、查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)
    时空限制:2s,128M
    (n,m≤5⋅10^4) 保证有序序列所有值在任何时刻满足([0,108^])

    sol

    树状数组套动态开节点的权值线段树。
    你需要完成以下这一系列操作:
    (Update(i,type)),把原数组中(i)位置上的数进行(type(=1 or-1))操作放到树状数组里面去。类比于树状数组的单点修改操作,这个的复杂度是(O(log_{2}^{2}n))
    (Sum(l,r,ql,qr)),统计位置位于([l,r]),且权值位于([ql,qr])之间的树的个数。易知我们可以拿(log n)棵线段树跟另外(log n)棵线段树作差。复杂度(O(log_{2}^{2}n))
    (Rank(l,r,k)),查找区间([l,r])中第(k)大的数是多少。这个就是。。。那个呀。复杂度(O(log_{2}^{2}n))
    我们来看这道题。首先数据离线然后离散化不解释。
    操作一,排名就是小于它的数的个数+1。直接调用(Sum(l,r,1,k-1))
    操作二,直接调用(Rank(l,r,k))
    操作三,两次调用(Update(pos,type)),第一次(type=-1),在原数组里改掉以后调用(type=1)
    操作四,前驱。先查(Sum(l,r,1,k-1)),若为0则输出-2147483647,否则输出(Rank(l,r,sum))(sum就是前面查的答案)
    操作四,后继。同理。先查(Sum(l,r,1,k)),若为r-l+1则输出2147483647,否则输出(Rank(l,r,sum+1))
    操作四五比较难搞,这里要敲黑板。
    然后这题就讲完了。

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 50005;
    struct tree{int ls,rs,num;}t[N*200];
    struct query{int opt,l,r,pos,k;}q[N];
    int n,m,a[N],o[N<<1],len,rt[N],tot,temp[2][20],cnt[2];
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    void Modify(int &x,int l,int r,int pos,int v)
    {
    	if (!x) x=++tot;
    	t[x].num+=v;
    	if (l==r) return;
    	int mid=l+r>>1;
    	if (pos<=mid) Modify(t[x].ls,l,mid,pos,v);else Modify(t[x].rs,mid+1,r,pos,v);
    }
    int Query(int x,int l,int r,int ql,int qr)
    {
    	if (l>=ql&&r<=qr) return t[x].num;
    	int mid=l+r>>1,s=0;
    	if (ql<=mid) s+=Query(t[x].ls,l,mid,ql,qr);
    	if (qr>mid) s+=Query(t[x].rs,mid+1,r,ql,qr);
    	return s;
    }
    int Find(int l,int r,int k)
    {
    	if (l==r) return l;
    	int mid=l+r>>1,sum=0;
    	for (int i=1;i<=cnt[1];i++) sum+=t[t[temp[1][i]].ls].num;
    	for (int i=1;i<=cnt[0];i++) sum-=t[t[temp[0][i]].ls].num;
    	if (k<=sum)
    	{
    		for (int i=1;i<=cnt[1];i++) temp[1][i]=t[temp[1][i]].ls;
    		for (int i=1;i<=cnt[0];i++) temp[0][i]=t[temp[0][i]].ls;
    		return Find(l,mid,k);
    	}
    	else
    	{
    		for (int i=1;i<=cnt[1];i++) temp[1][i]=t[temp[1][i]].rs;
    		for (int i=1;i<=cnt[0];i++) temp[0][i]=t[temp[0][i]].rs;
    		return Find(mid+1,r,k-sum);
    	}
    }
    void Update(int pos,int v)
    {
    	for (int i=pos;i<=n;i+=i&-i)
    		Modify(rt[i],1,len,a[pos],v);
    }
    int Sum(int l,int r,int ql,int qr)
    {
    	if (ql>qr) return 0;
    	int sum=0;
    	for (int j=r;j;j-=j&-j) sum+=Query(rt[j],1,len,ql,qr);
    	for (int j=l-1;j;j-=j&-j) sum-=Query(rt[j],1,len,ql,qr);
    	return sum;
    }
    int Rank(int l,int r,int k)
    {
    	cnt[1]=cnt[0]=0;
    	for (int j=r;j;j-=j&-j) temp[1][++cnt[1]]=rt[j];
    	for (int j=l-1;j;j-=j&-j) temp[0][++cnt[0]]=rt[j];
    	return o[Find(1,len,k)];
    }
    int main()
    {
    	n=gi();m=gi();
    	for (int i=1;i<=n;i++) o[++len]=a[i]=gi();
    	for (int i=1;i<=m;i++)
    	{
    		q[i].opt=gi();
    		if (q[i].opt!=3) q[i].l=gi(),q[i].r=gi();
    		else q[i].pos=gi();
    		q[i].k=gi();
    		if (q[i].opt!=2) o[++len]=q[i].k;
    	}
    	sort(o+1,o+len+1);
    	len=unique(o+1,o+len+1)-o-1;
    	for (int i=1;i<=n;i++)
    	{
    		a[i]=lower_bound(o+1,o+len+1,a[i])-o;
    		Update(i,1);
    	}
    	for (int i=1;i<=m;i++)
    	{
    		if (q[i].opt!=2) q[i].k=lower_bound(o+1,o+len+1,q[i].k)-o;
    		if (q[i].opt==1)
    			printf("%d
    ",Sum(q[i].l,q[i].r,1,q[i].k-1)+1);
    		if (q[i].opt==2)
    			printf("%d
    ",Rank(q[i].l,q[i].r,q[i].k));
    		if (q[i].opt==3)
    		{
    			Update(q[i].pos,-1);
    			a[q[i].pos]=q[i].k;
    			Update(q[i].pos,1);
    		}
    		if (q[i].opt==4)
    		{
    			int sum=Sum(q[i].l,q[i].r,1,q[i].k-1);
    			if (!sum) printf("-2147483647
    ");
    			else printf("%d
    ",Rank(q[i].l,q[i].r,sum));
    		}
    		if (q[i].opt==5)
    		{
    			int sum=Sum(q[i].l,q[i].r,1,q[i].k);
    			if (sum==q[i].r-q[i].l+1) printf("2147483647
    ");
    			else printf("%d
    ",Rank(q[i].l,q[i].r,sum+1));
    		}
    		
    	}
    	return 0;
    }
    
  • 相关阅读:
    laravel中使用include和component方法中的一点小区别
    【解决】Converting circular structure to JSON
    NUXT中使用axios,自己项目测试记录
    iPhone“连到系统上的设备没有发挥作用”原因分析及解决方法 20200105
    vue-touch不能上下滑动的问题【解决】
    动态加载swiper,默认显示最后一个swiper-slide怎么办
    CentOS 7 修改开机等待时间
    使用IIS管理器搭建FTP服务器以及其启用虚拟主机名
    织梦后台删除子栏目不成功的解决方法
    去除织梦标签[field:image/]所产生的宽高
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8196400.html
Copyright © 2020-2023  润新知