[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('\n');
}
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\)就没事了

好暴力啊!

posted @ 2020-08-29 10:35  srf  阅读(218)  评论(0编辑  收藏  举报