Old Driver Tree(ODT 老驱动树)

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

O D T ODT ODT真是一个 暴 力 暴力 神奇的东西

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

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

于是就将这个区间缩成一个点,用 s e t set set维护一下所有点

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

具体实现:


初始化

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

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

用结构体实现

#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;}
};

其主要操作就 2 2 2个:

看代码应该很好理解

S p l i t : 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;
}

A s s i g n : Assign: Assign用于处理区间覆盖,将一段区间提出来缩成一个点

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为例)

A d d 区 间 加 Add区间加 Add:直接遍历 s e t set set l l l~ r r r中的所有点

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

K t h Kth Kth查询区间第 k k k小:将区间所有点的信息 ( l , r , v a l ) (l,r,val) (l,r,val)加到一个 v e c t o r vector vector

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

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;
}

S u m Sum Sum:区间所有数的 k k k次方之和

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;
}

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

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

由初中数学可以证明每次 A s s i g n Assign Assign的期望长度约为 1 3 \frac13 31

不明白的可以自己百度

所以每次 A s s i g n Assign Assign会使 m m m变成 2 3 m \frac23m 32m并有概率产生2个新的区间

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

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

然后大概就是 O ( n l o g n ) O(nlogn) O(nlogn)了…

(赶紧逃)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值