珂朵莉树(学习笔记)

推荐一篇博客,珂朵莉树本来就是一种暴力数据结构,思想很简单,实现也比线段树简单一点.学习珂朵莉树其实只要学好了STL的\(set\)的就行了.

因为珂朵莉树实在是没有什么要讲的东西,然后该讲的上面那篇博客也讲得差不多了.这里我就只讲几个珂朵莉树能够实现的几个基本操作.

先放上几套模板题.

CF896C Willem, Chtholly and Seniorious珂朵莉树的入坑题???

[SCOI2010]序列操作

语文1(chin1)- 理理思维

CF915E Physical Education Lessons

[SHOI2015]脑洞治疗仪

分裂操作(前置操作,实现其他操作的基础)

inline IT split(int pos){
	IT it=s.lower_bound(node(pos));
	if(it!=s.end()&&it->l==pos)return it;
	--it;
	int l=it->l,r=it->r;ll val=it->val;
	s.erase(it);
	s.insert(node(l,pos-1,val));
	return s.insert(node(pos,r,val)).first;
}

操作一:区间赋值(这是珂朵莉树的必备操作,如果没有这个操作珂朵莉树可能真的就是\(n^2\)暴力了)

inline void assign(int l,int r,int val){//将[l,r]赋值为val
	IT itr=split(r+1),itl=split(l);
	s.erase(itl,itr);
	s.insert(node(l,r,val));
}

操作二:区间修改,将\([l,r]\)中每个值加上val

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

操作三:区间k小值

inline ll kth(int l,int r,int k){
    vector<pair<int,int> >q;
    IT itr=split(r+1),itl=split(l);
    for(;itl!=itr;++itl)
		q.push_back(pair<int,int>(itl->val,itl->r-itl->l+1));
    sort(q.begin(),q.end());
    for(vector<pair<int,int> >::iterator it=q.begin();it!=q.end();++it){
        k-=it->second;
        if(k<=0)return it->first;
    }
}

操作四:区间\([l,r]\)总共有多少个va

inline int ask1(int l,int r,int val){
	int ans=0;
	IT itr=split(r+1),itl=split(l);
	for(;itl!=itr;++itl)
		if(itl->val==val)ans+=(itl->r-itl->l+1);
	return ans;
}

操作五:区间\([l,r]\)中最多有多少个连续的val

inline int ask2(int l,int r,int val){
    int ans=0,cnt=0;
    IT itr=split(r+1),itl=split(l);
    for(;itl!=itr;++itl){
        if(itl->val!=val)ans=max(ans,cnt),cnt=0;
        else cnt+=itl->r-itl->l+1;
    }
    return max(ans,cnt);
}

操作六:将区间[l,r]从小到大排序,这个与求区间k小是不同的,因为区间K小只需要将区间的数(拎出来)排序,然后求第k个,不需要更改原区间的数的顺序.(代码中保证了区间中的数在1到26之间,所以可以开桶)

void get_sort(int l,int r){
    memset(sum,0,sizeof(sum));
    IT itr=split(r+1),itl=split(l),it=itl;
    for(;it!=itr;++it)sum[it->val]+=it->r-it->l+1;
    s.erase(itl,itr);
    for(int i=1;i<=26;++i)
		if(sum[i]){
			s.insert(node(l,l+sum[i]-1,i));
			l+=sum[i];
		}
}

操作七:将区间[l1,r1]复制到区间[l2,r2]上,保证r1-l1=r2-l2,且两个区间不重叠.开一个vector,把\([l1,r1]\)放进vector,然后把\([l2,r2]erase\)掉,再把\(vector\)里的\(insert\)\([l2,r2]\)中;

inline void change1(int l1,int r1,int l2,int r2){
    vector<node>q;q.clear();
    for(IT itr=split(r1+1),itl=split(l1);itl!=itr;++itl)q.push_back(*itl);
    IT itr=split(r2+1),itl=split(l2);s.erase(itl,itr);
    for(It i=q.begin();i!=q.end();++i)s.insert(node(i->l-l1+l2,i->r-l1+l2,i->val));
}

操作八:将区间[l1,r1]与区间[l2,r2]交换,保证r1-l1=r2-l2,且两个区间不重叠.开两个\(vector\),像操作七一样即可.

inline void change2(int l1,int r1,int l2,int r2){
    if(l1>l2)swap(l1,l2),swap(r1,r2);
    vector<node>q1,q2;q1.clear(),q2.clear();
    for(IT itr=split(r1+1),itl=split(l1);itl!=itr;++itl)q1.push_back(*itl);
    for(IT itr=split(r2+1),itl=split(l2);itl!=itr;++itl)q2.push_back(*itl);
    IT itr=split(r1+1),itl=split(l1);s.erase(itl,itr);
    itr=split(r2+1),itl=split(l2);s.erase(itl,itr);
    for(It i=q1.begin();i!=q1.end();++i)s.insert(node(i->l-l1+l2,i->r-l1+l2,i->val));
    for(It i=q2.begin();i!=q2.end();++i)s.insert(node(i->l-l2+l1,i->r-l2+l1,i->val));
}

操作九:将区间[l,r]翻转.还是一个\(vector\),把\([l,r]\)放进vector,然后把\([l,r]erase\)掉,再把\(vector\)里的\(insert\)\([r,l]\)中.注意是\([r,l]\).

inline void Reverse(int l,int r){
    vector<node>q;q.clear();
    for(IT itr=split(r+1),itl=split(l);itl!=itr;++itl)q.push_back(*itl);
    IT itr=split(r+1),itl=split(l);s.erase(itl,itr);
    for(It i=q.begin();i!=q.end();++i)s.insert(node(r-i->r+l,r-i->l+l,i->val));
}

其他操作大家见仁见智就好了,反正怎么来都是暴力.优雅的暴力也是暴力.

posted on 2019-08-11 20:06  PPXppx  阅读(206)  评论(0编辑  收藏  举报