1. 程式人生 > 其它 >珂朵莉樹(ODT)

珂朵莉樹(ODT)

珂朵莉樹 ODT

主要內容

珂朵莉樹是基於資料隨機且有整體賦值操作而對序列操作的亂搞演算法。

它的主要思想是用 set 維護若干個數值上相同的區間,並暴力處理其他詢問。

建立

set 中,我們需要用結構體記錄每個區間的資訊:

struct NODE
{
	 int l,r;
	 mutable ll val; // mutable 表示可變的,便於在外邊修改 val 的值
	 NODE(int L,int R=-1,ll Val=0)l(L),r(R),val(Val){} // 相當於 (NODE){l,r,val}
	 bool friend operator < (NODE x,NODE y) { return x.l<y.l; } // 過載 <
};
set<NODE> s;

這樣再 set 中就可以自動按照左端點排序了,注意在初始化的時候加入 \([n+1,n+1]\) 的區間。

split

珂朵莉樹用 split 操作分裂出一堆區間後暴力操作。

inline auto split(int p)
{
	 auto it=s.lower_bound(NODE(p));
	 if(it!=s.end() && it->l==p) return it;
	 it--;
	 int l=it->l,r=it->r;
	 ll v=it->val;
	 s.erase(it);
	 s.insert(NODE(l,p-1,v));
	 return s.insert(NODE(p,r,v)).fi;
}

merge

如果只有 split 操作那 set 中元素豈不是爆炸?我們需要時不時將一些區間合併為一個區間才能保證複雜度。

inline void merge(int l,int r,int v)
{
	 auto itl=s.split(l),itr=s.split(r+1);
	 s.erase(itl,itr); // 用將 [itl,itr) 之間的元素全部刪除
	 s.insert(NODE(l,r,v));
}

其他操作

其他操作就可以直接暴力在 set 中搞了,下面以求區間內每個數的平方的和為例:

inline ll query(int l,int r)
{
	 auto itl=s.split(l),itr=s.split(r+1);
	 ll ret=0;
	 for(auto it=itl;it!=itr;it++)
	 	 ret+=1ll*(it->r-it->l+1)*it->v*it->v;
	 return ret;
}

例題

起源題:CF896C Willem, Chtholly and Seniorious

CF1423G Growing flowers

jpj:這題 800。

咕咕咕