zoukankan      html  css  js  c++  java
  • [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)就没事了

    好暴力啊!

  • 相关阅读:
    Node.js Event Loop 的理解 Timers,process.nextTick()
    Ajax关于readyState(状态值)和status(状态码)的研究
    原生 JavaScript 实现 AJAX、JSONP
    Python selenium.webdriver.chrome.options.Options() Examples
    【python】统一转换日期格式dateutil.parser.parse
    python读取doc
    大规模爬虫流程总结
    如何巧妙的利用selenium和requests组合来进行操作需要登录的页面
    使用pandas进行数据清洗
    twilio打电话和发短信
  • 原文地址:https://www.cnblogs.com/s-r-f/p/13581247.html
Copyright © 2011-2022 走看看