題解 P2710 數列

2022-07-25 16:57:25 字數 3883 閱讀 2961

區間操作集大成者……?

可能吧……

by某位不願意透露姓名的巨學

本題需要實現:

共七個操作

全部操作都涉及到序列

於是我們考慮使用splay或者fhq-treap實現

這裡使用fhq-treap

前置芝士

蛤?不會?左轉度娘/必應娘/谷歌娘

左轉p3391題解區,包教包會,不會不要錢本來就不要錢吧

左轉p4513

非必要實際上不用這個方法用暴力插入也能過,但可能需要卡卡常

0.初始定義

struct note 

inline void clear()

};

-1.資訊上傳,標記下放

inline void up(int o) 

if (rs)

}inline void flip(int o)

inline void cvr(int o,int val)

inline void down(int o)

if (rs)

} if (t[o].cvr!=inf)

if (rs)

} t[o].tag=0;

t[o].cvr=inf;

}

1.插入操作

第乙個要實現的操作,然而並不是最簡單的

我們可以選擇暴力插入,但……

這樣子做的時間複雜度是o(qlogn)的,其中q為插入序列中數的個數

如何優化?

笛卡爾樹建樹!

自行度娘具體方法,這裡直接給出**

inline int build(int len,int a) 

t[cur].ch[0]=last;

up(cur);

if (top)

stk[++top]=cur;

} while(top)

return stk[1];

}

返回的是新建樹的根

有了這個函式,insert就非常好寫了

inline void insert(int pos,int len,int a)
時間複雜度o(q+logn),其中q為序列中數的個數

2.delete操作

把要刪除的區間提取出來直接中序歷刪除即可

注意垃圾**

void recycle(int o) 

if (ls)

trash.push(o);

if (rs)

}inline void remove(int pos,int len)

時間複雜度o(logn+q)

3.reverse操作

左轉文藝平衡樹

注意標記下放

inline void reverse(int pos,int len)
時間複雜度o(logn)

4.make-same操作

全場最煩操作(因為要手動更新

inline void cover(int pos,int len,int val)
時間複雜度o(logn)

5.三大詢問

因為**都很無腦就放一起了

inline int get_sum(int pos,int len) 

inline int get_max_sum(int pos,int len)

inline int ask_point(int pos)

時間複雜度o(logn)

最後,讓我們看看核心函式:merge和split

void split(int x,int k,int &a,int &b) 

down(x);

if (k>t[t[x].ch[0]].siz) else

}int merge(int x,int y)

if (y)

if (!x||!y)

if (t[x].rd遵循原則:用時間換安全

具體來講,在寫這兩個函式的時候,能上傳下放就上傳下放,保障安全

最後的最後,一點個人感想

前前後後調了半個寒假,還是很有收穫的

up,down,merge,split四個核心函式一定要好好理解,不然一出bug就……

放總體** 我知道你們只想看這個

#include #include #include #include #include #include #include #include using namespace std;

inline int random()

inline void read(int &x)

ch=getchar();

} while(ch>='0'&&ch<='9')

x*=f;

}queuetrash;//????????

int root;//???????

const int inf=2e9;

struct note

inline void clear()

};int stk[500010],top;

struct fhq_treap

//??????

inline int new_node(int val)

//?????

inline void up(int o)

if (rs)

} //????

inline void flip(int o)

//????????????

inline void cvr(int o,int val)

//?????

inline void down(int o)

if (rs)

} if (t[o].cvr!=inf)

if (rs)

} t[o].tag=0;

t[o].cvr=inf;

} //???

//len:??????a:?????????

//?????????

inline int build(int len,int a)

t[cur].ch[0]=last;

up(cur);

if (top)

stk[++top]=cur;

} while(top)

return stk[1];

} //??????

//a???????

//b???????

//x???????????

//k??????????

void split(int x,int k,int &a,int &b)

down(x);

if (k>t[t[x].ch[0]].siz) else

} //??????

//x??????????

//y??????????

int merge(int x,int y)

if (y)

if (!x||!y)

if (t[x].rd>s;

if (s=="insert")

ft.insert(pos,len,a);

} else if(s=="delete") else if (s=="reverse") else if (s=="make-same") else if (s=="max-sum") else if (s=="get-sum") else

} return 0;

}

題解 P5175 數列

luogup5175 數列 n leq 10 這擺明要用矩陣 ans sum na i 2 a n x cdot a y cdot a rightarrow a n 2 x 2a 2 2xy cdot a a y 2a 2 所以我們可以知道 color a and a cdot a color 所以...

P1182 數列分段 Section II 題解

演算法思路 首先求最大值最小或最小值最大問題應用二分來直接二分出答案,其次寫出check函式判斷,由題意可得,答案的範圍一定在數列的最大值至數列所有項的和之間,於是我們可令l 數列中最大值,r 數列所有項的和,而check函式應判斷我們二分到的答案最少能分為幾段,如果段數大於m則答案在mid右側,否...

題解 P6435 EZEC 1 數列

傳送門 久違地來一波題解,來乙個數學角度推式子的方法 記第 k 次合併後的第 i 個數為 f 根據題意,所求即為 ans f 且有 f af bf c,f i 形式上,我們設 exists d wedge f d a f d b f d 則不難換算出 a b 1 d c 注意,只是形式上這樣設,d ...