Old Driver Tree(ODT 老驱动树)

ODTODT,中文称为老驱动树,又名珂朵莉树(虽然我看到老驱动莫名想笑)

ODTODT真是一个暴力神奇的东西

但是只有在数据随机且有区间覆盖操作的时候才有用(因为只有区间覆盖才会容易产生一段相同的区间)

因为考虑到每次覆盖了一个区间之后整个区间的数都是一样的了

于是就将这个区间缩成一个点,用setset维护一下所有点

这时候我们就可以方便的对其操作

具体实现:


初始化

考虑到每个点都是一段相同的区间

所以要维护区间左右端点和区间的值

用结构体实现

#define IT set<node>::iterator
#define pi pair<ll,int>
#define mp(x,y) make_pair(x,y)
struct node{
	int l,r;
	mutable ll val;
	node(int L,int R=-1,ll v=0):l(L),r(R),val(v){}
	bool operator < (const  node &a)const {return l<a.l;}
};

其主要操作就22个:

看代码应该很好理解

Split:Split: 将一段区间分成两段并返回后一段的开头,用作分离出一段特定区间来处理询问

inline IT split(int pos){
	IT it=st.lower_bound(node(pos));
	if(it!=st.end()&&it->l==pos)return it;
	it--;
	int l=it->l,r=it->r;
	ll val=it->val;
	st.erase(it);
	st.insert(node(l,pos-1,val));
	return st.insert(node(pos,r,val)).first;
}

AssignAssign:用于处理区间覆盖,将一段区间提出来缩成一个点

inline void assign(int l,int r,ll val){
	IT itr=split(r+1),itl=split(l);
	st.erase(itl,itr);
	st.insert(node(l,r,val));	
}

另外几个操作(以CodeForces-896C为例)

AddAdd区间加:直接遍历setsetll~rr中的所有点

inline void add(int l,int r,int val){
	IT itr=split(r+1),itl=split(l);
	for(;itl!=itr;itl++)itl->val+=val;
}

KthKth查询区间第kk小:将区间所有点的信息(l,r,val)(l,r,val)加到一个vectorvector

按大小和数量遍历到第kk个输出就是了

inline ll kth(int l,int r,int k){
	vector<pi>vec;
	IT itr=split(r+1),itl=split(l);
	for(;itl!=itr;itl++)
	vec.push_back(mp(itl->val,itl->r-itl->l+1));
	sort(vec.begin(),vec.end());
	for(vector<pi>::iterator it=vec.begin();it!=vec.end();it++){
		k-=it->second;
		if(k<=0)return it->first;
	}
	return -1;
}

SumSum:区间所有数的kk次方之和

inline ll ksm(ll a,ll b,ll mod){
	int res=1;a%=mod;
	for(;b;b>>=1,a=a*a%mod){
		if(b&1)res=res*a%mod;
	}
	return res;
}
inline ll sum(int l,int r,ll x,ll y){
    ll res=0;
    IT itr=split(r+1),itl=split(l);
    for(;itl!=itr;++itl)
    res+=(ksm(itl->val,x,y)*((itl->r-itl->l+1)%y))%y,res%=y;
    return res;
}

感性理解一下复杂度 网上找不到证明

设区间数为mm=nm,初始m=n

由初中数学可以证明每次AssignAssign的期望长度约为 13\frac13

不明白的可以自己百度

所以每次AssignAssign会使mm变成23m\frac23m并有概率产生2个新的区间

开始的时候相当于每次减少13\frac 13

后面由于mm少了产生的新区间也会有贡献

然后大概就是O(nlogn)O(nlogn)了…

(赶紧逃)

posted @ 2019-01-21 17:44  Stargazer_cykoi  阅读(280)  评论(0编辑  收藏  举报