珂朵莉樹(ODT)
阿新 • • 發佈:2022-03-24
珂朵莉樹 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。
咕咕咕