• BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay


    传送门

    题意

    给你一个长度为 $ n $ 有序数列 $ a $ ,进行 $ m $ 次操作,操作有如下几种:

    1. 查询 $ k $ 在区间 $ [l,r] $ 内的排名
    2. 查询区间 $ [l,r] $ 内排名为 $ k $ 的值
    3. 将 $ a[p] $ 修改为 $ k $
    4. 查询 $ k $ 在区间 $ [l,r] $ 内的前驱(前驱定义为小于 $ k $ ,且最大的数)
    5. 查询 $ k $ 在区间 $ [l,r] $ 内的后继(后继定义为大于 $ k $ ,且最小的数)

    题解

    线段树套splay。

    先将 $ n $ 个数插入线段树:对于每个 $ a[i] $,将线段树上到位置 $ i $ 的叶子节点的路径上的所有splay插入元素 $ a[i] $ 。

    操作1:区间 $ [l,r] $ 在线段树上对应了若干棵splay,将这些splay中小于 $ k $ 的元素个数累加,记为 $ sum $ ,$ sum+1 $ 即为答案。

    操作2:二分这个元素的值,然后进行操作1得到当前rank,对应地调整答案。

    操作3:将线段树上到位置 $ p $ 的叶子节点的路径上的所有splay删除 $ a[p] $ ,再插入 $ k $ ,然后更新 $ a[p] = k $ 。

    操作4:将区间 $ [l,r] $ 对应的所有splay中查询到的 $ k $ 的前驱取 $ max $ 即可。

    操作5:将区间 $ [l,r] $ 对应的所有splay中查询到的 $ k $ 的后继取 $ min $ 即可。

    最后,纪念一下我用pbds加map封装的的假splay......QAQ

    还有就是因为b站g++版本太老,null_type会CE,要改成null_mapped_type

    AC Code

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <ext/pb_ds/assoc_container.hpp>
    #include <ext/pb_ds/tree_policy.hpp>
    #define MAX_N 50005
    #define MAX_V 200005
    #define INF 2147483647
    
    using namespace std;
    using namespace __gnu_pbds;
    
    typedef tree<pair<int,int>,null_mapped_type,less<pair<int,int> >,rb_tree_tag,tree_order_statistics_node_update> Tree;
    typedef Tree::iterator git;
    
    struct Splay
    {
    	Tree t;
    	map<int,int> mp;
    	void ins(int x)
    	{
    		t.insert(make_pair(x,mp[x]=mp[x]+1));
    	}
    	void del(int x)
    	{
    		t.erase(make_pair(x,mp[x])),mp[x]=mp[x]-1;
    	}
    	int pre(int x)
    	{
    		if(t.empty()) return -INF;
    		git it=t.lower_bound(make_pair(x,0));
    		if(it==t.begin()) return -INF;
    		return (--it)->first;
    	}
    	int suc(int x)
    	{
    		if(t.empty()) return INF;
    		git it=t.upper_bound(make_pair(x,INF));
    		if(it==t.end()) return INF;
    		return it->first;
    	}
    	int kth(int x)
    	{
    		return t.find_by_order(x-1)->first;
    	}
    	int rk(int x)
    	{
    		return t.order_of_key(make_pair(x,1))+1;
    	}
    };
    
    int n,m;
    int a[MAX_N];
    Splay t[MAX_V];
    
    void ins(int p,int k,int l,int r,int x)
    {
    	t[k].ins(x);
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	if(p<=mid) ins(p,k*2+1,l,mid,x);
    	else ins(p,k*2+2,mid+1,r,x);
    }
    
    int getrk(int a,int b,int k,int l,int r,int x)
    {
    	if(a<=l && r<=b) return t[k].rk(x)-1;
    	int mid=(l+r)>>1,ans=0;
    	if(a<=mid) ans+=getrk(a,b,k*2+1,l,mid,x);
    	if(b>mid) ans+=getrk(a,b,k*2+2,mid+1,r,x);
    	return ans;
    }
    
    int getx(int a,int b,int k)
    {
    	int l=0,r=INF;
    	while(r-l>1)
    	{
    		int mid=(l+r)>>1;
    		if(getrk(a,b,0,1,n,mid)<=k-1) l=mid;
    		else r=mid;
    	}
    	return l;
    }
    
    void upd(int p,int k,int l,int r,int x)
    {
    	t[k].del(a[p]),t[k].ins(x);
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	if(p<=mid) upd(p,k*2+1,l,mid,x);
    	else upd(p,k*2+2,mid+1,r,x);
    }
    
    int getpre(int a,int b,int k,int l,int r,int x)
    {
    	if(a<=l && r<=b) return t[k].pre(x);
    	int mid=(l+r)>>1,ans=-INF;
    	if(a<=mid) ans=max(ans,getpre(a,b,k*2+1,l,mid,x));
    	if(b>mid) ans=max(ans,getpre(a,b,k*2+2,mid+1,r,x));
    	return ans;
    }
    
    int getsuc(int a,int b,int k,int l,int r,int x)
    {
    	if(a<=l && r<=b) return t[k].suc(x);
    	int mid=(l+r)>>1,ans=INF;
    	if(a<=mid) ans=min(ans,getsuc(a,b,k*2+1,l,mid,x));
    	if(b>mid) ans=min(ans,getsuc(a,b,k*2+2,mid+1,r,x));
    	return ans;
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]),ins(i,0,1,n,a[i]);
    	int opt,l,r,k,p;
    	while(m--)
    	{
    		scanf("%d",&opt);
    		if(opt==1)
    		{
    			scanf("%d%d%d",&l,&r,&k);
    			printf("%d
    ",getrk(l,r,0,1,n,k)+1);
    		}
    		if(opt==2)
    		{
    			scanf("%d%d%d",&l,&r,&k);
    			printf("%d
    ",getx(l,r,k));
    		}
    		if(opt==3)
    		{
    			scanf("%d%d",&p,&k);
    			upd(p,0,1,n,k),a[p]=k;
    		}
    		if(opt==4)
    		{
    			scanf("%d%d%d",&l,&r,&k);
    			printf("%d
    ",getpre(l,r,0,1,n,k));
    		}
    		if(opt==5)
    		{
    			scanf("%d%d%d",&l,&r,&k);
    			printf("%d
    ",getsuc(l,r,0,1,n,k));
    		}
    	}
    }
    
  • 相关阅读:
    iOS开发——网络篇——文件下载(NSMutableData、NSFileHandle、NSOutputStream)和上传、压缩和解压(三方框架ZipArchive),请求头和请求体格式,断点续传Range
    聚类_七月算法4月机器学习班第10次课程笔记
    codejam环境熟悉—Minimum Scalar Product
    STL源码剖析读书笔记--第6章&第7章--算法与仿函数
    STL源码分析读书笔记--第5章--关联式容器
    STL源码剖析读书笔记--第四章--序列式容器
    STL源码分析读书笔记--第二章--空间配置器(allocator)
    树莓PI上跑爬虫
    树莓PI安装jdk1.8,ant,maven【转】
    myeclipse10 安装 testng插件
  • 原文地址:https://www.cnblogs.com/Leohh/p/9205400.html
Copyright © 2020-2023  润新知