[OI笔记]珂朵莉树学习小结

珂朵莉树,一看就觉得很玄学
大概就是把若干个内部的值一样/等价/可以用少量的东西来表示出 的区间丢进(set) / 平衡树 里去,
然后和暴力一样维护题目要求的信息。

先来看一道题 CF896C

珂朵莉树的应用的重要条件:数据随机。

这样,操作序列中有期望 $ O(frac{m}{t}) $ 次 ((t)为操作种类数)
(Assign) (.)

而每次(Assign)之后(,)区间个数会大大减小(,)复杂度才有所保证。

(1) (Spilt(pos)) 分离操作

作用:将pos所在区间([L,R])分解为([L,pos-1])([pos,R]).

#define IT set<Node>::iterator
IT spilt(int pos){
	IT it = s.lower_bound(Node(pos));
	if (it->l == pos) return it;
	--it;
	int L = it->l,R = it->r; LL V = it->v;
	s.erase(it);
	s.insert(Node(L,pos-1,V));
	return s.insert(Node(pos,R,V)).first; 
}

(2) (Assign(l,r,v)) 推平操作

作用:将(set)中的([l,r])分解出来并推平成一段区间。

void Assign(int l,int r,LL val = 0){
	IT itl = spilt(l),itr = spilt(r+1);
	s.erase(itl,itr);
	s.insert(Node(l,r,val));
}

(3)、其他操作:都是暴力吧。。。 (() 实际上前两个操作也是暴力(雾) ())

void Add(int l,int r,int val){
	IT itl = spilt(l),itr = spilt(r+1);
	for (; itl != itr; ++itl) itl->v += val;
}
LL Kth(int l,int r,int k){
	IT itl = spilt(l),itr = spilt(r+1);
	vector<pair<LL,int> >rt; rt.clear();
	for (; itl != itr; ++itl) rt.push_back(pair<LL,int>(itl->v,itl->r - itl->l + 1));
	sort(rt.begin(),rt.end());
	for (vector<pair<LL,int> >::iterator it = rt.begin(); it != rt.end(); ++it){
		k -= it->second;
		if (k <= 0) return it->first;
	}
	return -1;
}
LL Power(int l,int r,int val,int p){
	IT itl = spilt(l),itr = spilt(r+1);
	LL ret = 0;
	for (; itl != itr; ++itl)
		ret = (ret + (LL)(itl->r - itl->l + 1)*qpow(itl->v,val,p)%p) % p;
	ret = (ret + p) % p;
	return ret;
}

代码:

#include <bits/stdc++.h>
#define LL long long
using namespace std;
inline int read(){
    int x = 0,f = 1; char c = getchar();
    while (c != EOF && !isdigit(c)) {if (c == '-') f = -1;c = getchar();}
    while (c != EOF && isdigit(c)) {x = x * 10 + c - '0';c = getchar();}
    return x * f;
}
inline void write(LL x){
    int k = 0;char put[20];
    if (!x) putchar('0');
    if (x < 0) putchar('-'),x = -x;
    while (x)  put[++k] = x % 10 + '0',x /= 10;
    while (k)  putchar(put[k]),--k;
	putchar('
');
}
namespace READ{
	LL seed,ret;
	inline int rnd(){
		ret = seed;
		seed = (seed * 7 + 13) % 1000000007;
		return ret;
	}
}
using namespace READ;
LL qpow(LL a,LL b,LL p){
	a %= p; LL ret = 1;
	while (b) { if (b&1) ret = ret*a%p; a = a*a%p,b>>=1; } return ret;
}
struct Node{
	int l,r; mutable LL v;
	Node (int ll,int rr = -1,LL val = 0){l = ll,r = rr,v = val;}
	bool operator < (const Node x) const{ return l < x.l; }
};
set<Node>s;
#define IT set<Node>::iterator
IT spilt(int pos){
	IT it = s.lower_bound(Node(pos));
	if (it->l == pos) return it;
	--it;
	int L = it->l,R = it->r; LL V = it->v;
	s.erase(it);
	s.insert(Node(L,pos-1,V));
	return s.insert(Node(pos,R,V)).first; 
}
void Assign(int l,int r,LL val = 0){
	IT itl = spilt(l),itr = spilt(r+1);
	s.erase(itl,itr);
	s.insert(Node(l,r,val));
}
void Add(int l,int r,int val){
	IT itl = spilt(l),itr = spilt(r+1);
	for (; itl != itr; ++itl) itl->v += val;
}
LL Kth(int l,int r,int k){
	IT itl = spilt(l),itr = spilt(r+1);
	vector<pair<LL,int> >rt; rt.clear();
	for (; itl != itr; ++itl) rt.push_back(pair<LL,int>(itl->v,itl->r - itl->l + 1));
	sort(rt.begin(),rt.end());
	for (vector<pair<LL,int> >::iterator it = rt.begin(); it != rt.end(); ++it){
		k -= it->second;
		if (k <= 0) return it->first;
	}
	return -1;
}
LL Power(int l,int r,int val,int p){
	IT itl = spilt(l),itr = spilt(r+1);
	LL ret = 0;
	for (; itl != itr; ++itl)
		ret = (ret + (LL)(itl->r - itl->l + 1)*qpow(itl->v,val,p)%p) % p;
	ret = (ret + p) % p;
	return ret;
}

LL n,m,vmax,op,l,r,x,y;
int main(){
	int i;
	n = read(),m = read(),seed = read(),vmax = read();
	s.insert(Node(0,0,0ll));
	for (i = 1; i <= n; ++i) x = rnd() % vmax + 1,s.insert(Node(i,i,x));
	s.insert(Node(n+1,n+1,0ll));
	while (m--){
		op = rnd() % 4 + 1,l = rnd() % n + 1,r = rnd() % n + 1;
		if (l > r) swap(l, r);
		if (op == 3) x = rnd() % (r-l+1) + 1;
		else x = rnd() % vmax + 1;
		if (op == 4) y = rnd() % vmax + 1;
		
		if (op == 1) Add(l,r,x);
		else if (op == 2) Assign(l,r,x);
		else if (op == 3) write(Kth(l,r,x));
		else write(Power(l,r,x,y));
	}
    return 0;
}

是不是很短啊qwq

然后还有,珂朵莉树还可以扩展到二维,所以可以把操作丢进(struct)里面去,然后把一维珂朵莉树当成(Node),用(set)维护一波即可。

以此类推可以扩展到任意高维。只要不(MLE),不(TLE)就没事了

好暴力啊!

原文地址:https://www.cnblogs.com/s-r-f/p/13581247.html