區間操作集大成者……?
可能吧……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 ...