珂朵莉树

珂朵莉树

珂朵莉树是暴力解决区间问题的一种优化方式,但本质上依旧是暴力,且在数据随机性很大的时候才会有较高的得分。

虽然珂朵莉树名字中有树,但其实只是区间的拆分合并,跟树没有关系。

比如一开始有区间\([1,25]\),现在更改\([5,17]\),那就把\([1,25]\)拆成\([1,4],[5,17],[18,25]\)。现在再更改\([8,25]\),那就把\([5,17]\)拆成\([5,7]\)\([8,17]\),再将\([8,17]\)\([18,25]\)合并,变成\([8,25]\),于是现在就有区间\([1,4],[5,7],[8,25]\)

然后用\(set\)或者平衡树或者别的方法维护就好了。

这里给出用\(set\)维护的代码。

注意,要先\(split(r+1)\)\(split(l)\)

\(s.insert(x).first\)指插入这个数后这个数在的地址

\(s.insert(x).second\)指是否成功插入这个数,成功插入即原集合无\(x\)

#include<bits/stdc++.h>
using namespace std;
#define S_it set<node>::iterator
#define v(it) it->v
#define l(it) it->l
#define r(it) it->r
int n,q,ans;
struct node
{
	int l,r;
	mutable bool v;
	node(int L,int R=-1,bool V=0){l=L;r=R;v=V;}
	friend bool operator<(node a,node b)
	{
		return a.l<b.l;
	}
};
set<node>S;

S_it split(int pos)
{
	S_it it=S.lower_bound(node(pos));
	
	if(it!=S.end()&&l(it)==pos) return it;
	
	it--;
	int l=l(it),r=r(it),v=v(it);
	S.erase(it);
	S.insert(node(l,pos-1,v));
	return S.insert(node(pos,r,v)).first;
}

void put(int l,int r,int k)
{
	S_it itr=split(r+1);
	S_it itl=split(l);
	for(S_it it=itl;it!=itr;it++) ans-=v(it)*(r(it)-l(it)+1);
	
	S.erase(itl,itr);
	S.insert(node(l,r,k));
	ans+=k*(r-l+1);
}

int main()
{
	scanf("%d %d",&n,&q);
	ans=n;
	S.insert(node(1,n,1));
	for(int i=1,l,r,k;i<=q;++i)
	{
		scanf("%d %d %d",&l,&r,&k);
		put(l,r,k-1);
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2020-11-04 08:35  林生。  阅读(134)  评论(0)    收藏  举报