zoukankan      html  css  js  c++  java
  • BZOJ3065 带插入区间K小值

    带插入区间K小值

    从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i]。跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴。这时跳蚤国王决定理性愉悦一下,查询区间k小值。他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少。
    这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问。
    这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少。
    这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问。(orz 主席树)
    这时伏特发现有些迟到的跳蚤会插入到这一行的某个位置上,他感到非常生气,因为……他不会做了。
    请你帮一帮伏特吧。
    快捷版题意:带插入、修改的区间k小值在线查询。

    原序列长度 <= 35000

    插入个数 <= 35000,修改个数 <= 70000,查询个数 <= 70000 ,0 <= 每时每刻的权值 <= 70000

    hzwer的题解

    得支持插入的树套树。由于没法旋转,所以只能选择替罪羊树。

    学习了一下替罪羊树,具体参见WJMZBMR《重量平衡树和后缀平衡树在信息学奥赛中的应用》。维基百科上面有证明。

    替罪羊树是一种不用旋转的平衡树,若一棵子树的左或右子树大小超过其大小55%-80%则暴力重构这棵子树,以此来维护平衡性,每个结点的期望重构次数是logn,实现可以自己脑补一下

    在替罪羊树每个结点放一棵包含该子树所有结点的权值线段树,也就是平衡树套权值线段树

    1. 由于外层是平衡树,那么就能实现插入一个结点:找到它的位置,在根到其路径上所有结点的线段树中插入这个值
    2. 查询区间第K大:找到这个区间包含若干棵子树,拿出他们的根的权值线段树,一起做个二分
    3. 修改与插入类似
    4. 当外层平衡树失衡的时候重构之。

    由于内存不够,我们还需要回收垃圾,即对数组的重复使用

    时间复杂度

    1. 查询区间第K大:我觉得把那些节点提取出来就是一个玄学操作,复杂度?据洛谷管理员noip说是(O(log n))的,那么查第k大就是(O(log^2n))的。但是我个人感觉这不是正确的上界。
    2. 重构:由于要回收节点,所以共用节点很麻烦,能力限制使我不能写线段树合并。但是暴力重构的复杂度还是(O(log^2 n))的。

    总时间复杂度(O((n+m) log^2 n)),但是常数问题导致我过不了洛谷上面时限1s的题。

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
    	rg T data=0,w=1;
    	rg char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-') w=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))
    		data=data*10+ch-'0',ch=getchar();
    	return data*w;
    }
    template<class T>il T read(rg T&x){
    	return x=read<T>();
    }
    typedef long long ll;
    using std::vector;
    
    co int N=7e4+1,LG=1e7; // memory limit
    int n,m;
    // Tree Tao Tree
    namespace T{
    	// Interval Tree
    	int tot,bin[LG];
    	int L[LG],R[LG],sum[LG];
    	il int construct() {return bin[0]?bin[bin[0]--]:++tot;}
    	il void destruct(int&x){
    		if(!x) return;
    		destruct(L[x]),destruct(R[x]);
    		bin[++bin[0]]=x,sum[x]=0,x=0; // edit 2: x=0
    	}
    	void insert(int&x,int l,int r,int p,int d){
    		if(!x) x=construct();
    		sum[x]+=d;
    		if(!sum[x]){
    			destruct(x);
    			return;
    		}
    		if(l==r) return;
    		int m=(l+r)/2;
    		if(p<=m) insert(L[x],l,m,p,d);
    		else insert(R[x],m+1,r,p,d);
    	}
    	int query(vector<int>&x,co vector<int>&vs,int l,int r,int k){
    		if(l==r) return l;
    		int s=0,m=(l+r)/2;
    		for(rg unsigned i=0;i<x.size();++i)
    			s+=sum[L[x[i]]];
    		for(rg unsigned i=0;i<vs.size();++i)
    			s+=(l<=vs[i]&&vs[i]<=m);
    		if(s>=k){
    			for(rg unsigned i=0;i<x.size();++i)
    				x[i]=L[x[i]];
    			return query(x,vs,l,m,k);
    		}
    		else{
    			for(rg unsigned i=0;i<x.size();++i)
    				x[i]=R[x[i]];
    			return query(x,vs,m+1,r,k-s);
    		}
    	}
    	// Scapegoat Tree
    	co double ratio=0.75; // edit 3:double
    	int root,pot[N];
    	int val[N],tree[N],ch[N][2];
    	void build(int&t,int l,int r){
    		if(l>r) return;
    		int m=(l+r)/2;
    		t=pot[m];
    		for(rg int i=l;i<=r;++i)
    			insert(tree[t],0,7e4,val[pot[i]],1);
    		if(l==r) return;
    		build(ch[t][0],l,m-1),build(ch[t][1],m+1,r); // edit 1:m-1 for balanced tree
    	}
    	void split(int t,int l,int r,vector<int>&x,vector<int>&vs){
    		int sl=sum[tree[ch[t][0]]],st=sum[tree[t]];
    		if(l==1&&r==st){
    			x.push_back(tree[t]);
    			return;
    		}
    		if(l<=sl+1&&sl+1<=r) vs.push_back(val[t]);
    		if(r<=sl) split(ch[t][0],l,r,x,vs);
    		else if(l>sl+1) split(ch[t][1],l-sl-1,r-sl-1,x,vs); // edit 3: 1,not 0
    		else{
    			if(l<=sl) split(ch[t][0],l,sl,x,vs);
    			if(r>sl+1) split(ch[t][1],1,r-sl-1,x,vs);
    		}
    	}
    	int query(int t,int l,int r,int k){
    		vector<int> x,vs;
    		split(t,l,r,x,vs);
    		return query(x,vs,0,7e4,k);
    	}
    	int modify(int t,int k,int v){
    		insert(tree[t],0,7e4,v,1);
    		int o,sl=sum[tree[ch[t][0]]];
    		if(sl+1==k) o=val[t],val[t]=v;
    		else if(sl>=k) o=modify(ch[t][0],k,v);
    		else o=modify(ch[t][1],k-sl-1,v);
    		insert(tree[t],0,7e4,o,-1);
    		return o;
    	}
    	void remove(int&t){
    		if(!t) return;
    		remove(ch[t][0]);
    		pot[++pot[0]]=t;
    		remove(ch[t][1]);
    		destruct(tree[t]),t=0; // edit 2:t=0
    	}
    	il void rebuild(int&t){
    		remove(t);
    		build(t,1,pot[0]);
    		pot[0]=0;
    	}
    	int tmp;
    	void insert(int&t,int k,int v){
    		if(!t){
    			t=++n;
    			val[t]=v,insert(tree[t],0,7e4,v,1);
    			return;
    		}
    		insert(tree[t],0,7e4,v,1);
    		int sl=sum[tree[ch[t][0]]];
    		if(sl>=k) insert(ch[t][0],k,v);
    		else insert(ch[t][1],k-sl-1,v);
    		if(sum[tree[t]]*ratio>std::max(sum[tree[ch[t][0]]],sum[tree[ch[t][1]]])){
    			if(tmp){ // edit 4: when rebuilding must change ch as well
    				rebuild(ch[t][tmp==ch[t][1]]);
    				tmp=0;
    			}
    		}
    		else tmp=t;
    	}
    }
    
    int main(){
    //	freopen("BZOJ3065.in","r",stdin);
    //	freopen("BZOJ3065.out","w",stdout);
    	read(n);
    	for(rg int i=1;i<=n;++i)
    		read(T::val[i]),T::pot[i]=i;
    	T::build(T::root,1,n);
    	read(m);
    	int lastans=0;
    	while(m--){
    		char opt[2];
    		scanf("%s",opt);
    		switch(opt[0]){
    			case 'Q':{
    				int l=read<int>()^lastans,r=read<int>()^lastans,k=read<int>()^lastans;
    				printf("%d
    ",lastans=T::query(T::root,l,r,k));
    				break;
    			}
    			case 'M':{
    				int k=read<int>()^lastans,v=read<int>()^lastans;
    				T::modify(T::root,k,v);
    				break;
    			}
    			case 'I':{
    				int k=read<int>()^lastans,v=read<int>()^lastans;
    				T::insert(T::root,k-1,v);
    				if(T::tmp){
    					T::rebuild(T::root);
    					T::tmp=0;
    				}
    				break;
    			}
    			default:assert(0);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Oracle常用命令大全(很有用,做笔记)
    表格驱动编程在代码中的应用
    mac 利用svn下载远程代码出现Agreeing to the Xcode/iOS license requires admin privileges, please re-run as root via sudo.
    FAILURE: Build failed with an exception.
    There is an internal error in the React performance measurement code.Did not expect componentDidMount timer to start while render timer is still in progress for another instance
    react native TypeError network request failed
    Android向系统相册中插入图片,相册中会出现两张 一样的图片(只是图片大小不一致)
    react-native Unrecognized font family ‘Lonicons’;
    react-native SyntaxError xxxxx/xx.js:Unexpected token (23:24)
    Application MyTest has not been registered. This is either due to a require() error during initialization or failure to call AppRegistry.registerComponent.
  • 原文地址:https://www.cnblogs.com/autoint/p/10383048.html
Copyright © 2011-2022 走看看