• ChthollyTree 模板


    这种暴力又可爱的数据结构真的相当讨喜。如果题目中有操作是推平一段区间的话,那么它多半就是一道 ODT 的题。如果题目还保证了数据随机的话,那么恭喜你,ODT 一定可以简单高效的解决这个问题;但如果出题人卡数据的话,ODT 一定会 T 的飞起。
    掌握 ODT 的难度是相当小的,只要理解到 split 和 assign 就好了,这两种操作也是相当简单。其他附加的操作也是在这两种操作的基础上怎么暴力怎么来。

    两道板子题

    CF896C

    传送们
    万恶之源,也是珂朵莉树的名字来源。

    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <set>
    #include <queue>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> PLI;
    const int N=1e5+10;
    const int mod=1e9+7;
    int n,m;
    LL seed,vmax,a[N];
    
    LL qpow(LL x,LL k,LL mod){
    	LL res=1;x%=mod;
    	while(k){
    		if(k&1) res=res*x%mod;
    		x=x*x%mod;k>>=1;
    	}
    	return res;
    }
    
    struct ChthollyTree{
    	#define setit set<Node>::iterator
    	struct Node{
    		int l,r;
    		mutable LL x;
    		friend bool operator < (Node a,Node b){return a.l<b.l;}
    	};
    	set<Node> st;
    	void build(){for(int i=1;i<=n+1;i++) st.insert(Node{i,i,a[i]});}
    	setit split(int pos){
    		setit it=st.lower_bound(Node{pos});
    		if(it!=st.end()&&it->l==pos) return it;
    		it--;
    		int l=it->l,r=it->r;LL x=it->x;
    		st.erase(it);
    		st.insert(Node{l,pos-1,x});
    		return st.insert(Node{pos,r,x}).first;
    	}
    	void assign(int l,int r,LL x){
    		setit itl=split(l),itr=split(r+1);
    		st.erase(itl,itr);
    		st.insert(Node{l,r,x});
    	}
    	void add(int l,int r,LL v){
    		setit itl=split(l),itr=split(r+1);
    		for(setit it=itl;it!=itr;it++) it->x+=v;
    	}
    	LL getnum(int l,int r,int k){
    		setit itl=split(l),itr=split(r+1);
    		vector<pair<LL,int> > vp;
    		for(setit it=itl;it!=itr;it++) vp.push_back({it->x,it->r-it->l+1});
    		sort(vp.begin(),vp.end());
    		for(pair<LL,int> p:vp){
    			k-=p.second;
    			if(k<=0) return p.first;
    		}
    		return -1;
    	}
    	LL asksum(int l,int r,int k,int mod){
    		setit itl=split(l),itr=split(r+1);
    		LL ans=0;
    		for(setit it=itl;it!=itr;it++)
    			ans=( ans+qpow(it->x,k,mod)*(it->r-it->l+1) )%mod;
    		return ans;
    	}
    }odt;
    
    int rnd(){
    	int ret=seed;
    	seed=(seed*7+13)%mod;
    	return ret;
    }
    
    int main(){
    	cin>>n>>m>>seed>>vmax;
    	for(int i=1;i<=n;i++) a[i]=rnd()%vmax+1;
    	odt.build();
    	while(m--){
    		int opt=rnd()%4+1,l=rnd()%n+1,r=rnd()%n+1,x,y;
    		if(l>r) swap(l,r);
    		if(opt==3) x=rnd()%(r-l+1)+1;
    		else x=rnd()%vmax+1;
    		if(opt==4) y=rnd()%vmax+1;
    		if(opt==1) odt.add(l,r,x);
    		else if(opt==2) odt.assign(l,r,x);
    		else if(opt==3) printf("%lld
    ",odt.getnum(l,r,x));
    		else if(opt==4) printf("%lld
    ",odt.asksum(l,r,x,y));
    	}
    	return 0;
    }
    

    2019太原理工新生预赛L题

    传送门
    稍微简单一些的典型的珂朵莉树的应用

    #include <iostream>
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    #include <set>
    #include <queue>
    using namespace std;
    typedef long long LL;
    const int N=1e5+10;
    int n,m;
    struct ChthollyTree{
    	#define setit set<Node>::iterator
    	struct Node{
    		int l,r;
    		mutable LL val;
    		friend bool operator < (Node a,Node b){return a.l<b.l;}
    	};
    	set<Node> s;
    	void build(){s.insert(Node{1,n,1});s.insert(Node{n+1,n+1,0});}
    	setit split(int pos){
    		setit it=s.lower_bound(Node{pos});
    		if(it!=s.end()&&it->l==pos) return it;
    		it--;
    		int l=it->l,r=it->r,val=it->val;
    		s.erase(it);
    		s.insert(Node{l,pos-1,val});
    		return s.insert(Node{pos,r,val}).first;
    	}
    	void assign(int l,int r,int val){
    		setit itl=split(l),itr=split(r+1);
    		s.erase(itl,itr);
    		s.insert(Node{l,r,val});
    	}
    	void sumtor(int l,int r){
    		setit itl=split(l),itr=split(r+1);
    		LL sum=0;
    		for(setit it=itl;it!=itr;it++) sum+=it->val*(it->r-it->l+1);
    		assign(l,r-1,0);
    		assign(r,r,sum);
    	}
    	int count(int l,int r){
    		setit itl=split(l),itr=split(r+1);
    		set<LL> st;
    		int ans=0;
    		for(setit it=itl;it!=itr;it++) if(it->val) st.insert(it->val);
    		return st.size();
    	}
    }odt;
    
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    
    int main(){
    	n=read();m=read();
    	odt.build();
    	for(int i=1,opt,l,r;i<=m;i++){
    		opt=read(),l=read(),r=read();
    		if(opt==1) odt.assign(l,r,1);
    		else if(opt==2) odt.sumtor(l,r);
    		else if(opt==3) printf("%d
    ",odt.count(l,r));
    	}
    	return 0;
    }
    
  • 相关阅读:
    mysqldump指定编码导出数据
    centos 自带mysql卸载时出现无法卸载情况
    Linux下如何彻底删除MySQL
    输出一行字符串中的最长单词---调用函数
    span设置固定宽度
    如何使用Reaver破解Wi-Fi网络的WPA密码
    kernel hexdump分析 (2.0)
    C++基础学习笔记----第七课(面向对象的基本概念)
    有关java中的final关键字
    测试framebuffer
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12433509.html
Copyright © 2020-2023  润新知