noip級別模板小復習
阿新 • • 發佈:2018-11-11
不能 目標 eap 要求 記憶化搜索 考點 https st表 bst
不是很noip的知識點就不寫了。
dij什麽的太easy就不寫了。
縮點
- 註意\(Tarjan\)在縮邊雙和求強聯通分量時候的區別。
- 一個要判斷是否在棧內一個不要。
- 最後\(topsort\)來\(dp\),或者記憶化搜索,但是一定要記得初值為\(-1\)。
- 考慮圖不聯通。
負環
- 考慮圖不聯通。
- 一開始\(dis=0\),判斷最短路長度大於\(n\)會好一些。
- \(dfs\)型\(spfa\)是指數級的。
ST表
- 註意是\(i\)到\(i+2^k-1\)。
- 所以預處理的時候不要減1,因為已經減過了。查詢的時候要加1因為要把減去的1去掉。
Mx[j][i]=max(Mx[j-1][i],Mx[j-1][i+(1<<(j-1))]); printf("%d\n",max(Mx[k][l],Mx[k][r-(1<<k)+1]));
- \(O(n)\)預處理\(log\)。
線性基
- 用於查詢多個數異或問題,本質是高斯消元,也可以用來解方程(\(flash\)的考試題)。
- 記得\(1ll\),線性基的值域與原數組的值域相同,且各個之間線性無關。
- 如果要查詢某個數,就是查找某個數是否可以由這\(n\)個數中任一個數異或得到。首
- 從高到低掃這個數的每一位,如果這第\(i\)位為\(1\),就異或上\(P_i\),然後知道處理到最後一位。如果變成 \(0\) 了,那麽就是可以的。
- 查詢第\(k\)大數。
- 查詢異或集合中k小值
- 我們考慮改造一下線性基,使得每一位互相獨立。
- 如果\(j<i\),且\(p_i\)的第\(j\)
- 這樣,對於二進制的每一位\(i\)。只有\(p_i\)這一位是\(1\),其他的都是\(0\)。
- 同樣,這個線性基的本質也是沒有改變的。
- 我們查詢的時候,將\(k\)進行二進制拆分,如果第\(i\)位是\(1\),就異或上線性基中第\(i\)個元素,最終得出的答案就是\(k\)小值。
- 此外,需要對非滿秩的矩陣進行特判。因為其存在\(0\)的結果,如果要求最小,那麽就是\(0\)。
- 如果不是,那麽就是求當前矩陣下的第\((k-1)\)小。
splay 區間反轉
- 和\(lct\)一樣,註意棧序下放標記
S[S[0]=1]=x; for(R i=x;fa[i];i=fa[i])S[++S[0]]=fa[i]; while(S[0])push(S[S[0]--]);
- 一定要記得先\(find\)到目標點再轉到根而不是直接做。這裏的\(find\)和整體二分是不一樣的!
push(x);
if(k<=sz[ls])x=ls;
else if(k==sz[ls]+1){spl(x,gl);return x;}
else k-=(sz[ls]+1),x=rs;
- 提醒幾個常見小錯誤:
void rot(R x){
R y=fa[x],z=fa[y],k=son(x);
ch[z][son(y)]=x,fa[x]=z;
ch[y][k]=ch[x][k^1],fa[ch[x][k^1]]=y;
ch[x][k^1]=y,fa[y]=x;upd(y);
}
- \(rot\)要\(upd(y)\),而不是\(upd(x)\),如果都\(upd\)要先\(y\)再\(x\),不要搞反。
- 註意一開始要先記下來\(x\)是哪一個兒子,然後先拆開,再接起來。
for(R y=fa[x];y!=gl;rot(x),y=fa[x])
if(fa[y]!=gl)son(x)^son(y)?rot(x):rot(y);
upd(x);if(!gl)rt=x;
- 記得判斷\(y\)和\(gl\)的關系再決定轉一次還是兩次還是不轉。
- 一定記得更新\(x\)和\(rt\)。
splay 普通平衡樹
- 每次打這個都像在做模擬題……。
兩個log的樹狀數組把一個log的splay掉起來打treap只會過兩個月現在早就忘了- 太麻煩了,還不如樹狀數組或者線段樹。
- 反正你又沒有區間反轉。
- 太熱了不寫了
咕咕。
樹鏈剖分
- 剖分之後一般是搞個線段樹對\(dfn\)序維護。
- 樹上路徑就暴力跳重鏈條,兩個\(log\)。
- 子樹信息就直接是\(dfn\)到\(dfn+sz-1\)的連續區間,一個\(log\)。
- 如果是維護兒子信息就是\(bfs\)序 [SDOI2012]集合
- 但是我不會啊,咕。
倍增
- 太普及了。
左偏樹
- 可並堆,註意不能路徑壓縮。
- 合並的時候根據堆的屬性來判斷,合並在右子樹。
- 然後強制向左偏,我的習慣是深度向左偏。
- 記得更新\(d_i=d_{rs}+1\)。
- 刪除元素就把兩個兒子並起來。
kmp
- 核心思想是嘗試匹配。
- 求\(next\)的時候是
j=f[i-1];
while(j>=0&&T[i]!=T[j+1])j=f[j];
if(T[i]==T[j+1])f[i]=j+1;
else f[i]=-1;
- 也就是不斷嘗試能否接上一個新的後綴,否則就不斷跳\(next\),直到為\(-1\)。
- 查詢的時候是
j=f[j-1]+1;
,也就是往前走一個,再調\(next\),再往後走一個,也就是\(j\)失配,\(j-1\)配對好了,那麽利用\(j-1\)的\(next\),再往後走一個。
AC自動機
- 主要思想是\(fail\)樹。
- 先建好\(trie\),然後建\(fail\),然後每次匹配的時候都把\(fail\)的信息都收集一邊。
trie
- 難道你會了\(ac\)自動機還不會\(trie\)??
- 可持久化:和主席樹差不多,序列就是相差,樹上就是減去兩倍\(lca\)
- 啟發式合並:和線段樹啟發合並差不多,也是一個\(merge\)。
最小生成樹
- 本來想補一下\(B\)算法。
- 但是咕咕了。
dinic
- 記得當前弧優化,邊從\(2\)開始。
- 主要技巧在建圖,後面都是板子。
最小費用最大流
- 同上。
主席樹
- 動態開點,一般和別的數據結構結合在一起。
- 序列右邊繼承左邊,樹上兒子繼承父親。
點分治
- 你家\(noip\)考點分治??咕咕。
manacher
- 記錄最遠到達的位置和中心。
- 然後就知道了當前點的半徑下界是對稱過去的半徑。
- 然後暴力更新當前半徑,更新最遠距離和中心。
模擬退火
- 系統鐘
db Tim(){return (db)clock()/(db)CLOCKS_PER_SEC;}
- 生成一個於\(T\)大小相關的隨機,帶正負。
#define RD T*(rand()*2-RAND_MAX)
- 接受更劣解的概率
exp((ans-now)/T)*RAND_MAX>rand())
- 註意,\(now\)是當前答案,\(ans\)是當前\(sa\)的最優解,記得保存全局最優解\(bst\)。
- 隨機數組
random_shuffle(x+1,x+n+1);
CDQ
- 每次強制計算跨過中點的貢獻。
kdtree
- 註意替罪羊的重構方法。
最小循環表示法
- 今天才學。
- 先倍長,初始時,讓\(i=0\),\(j=1\),\(k=0\),其中\(i\),\(j\),\(k\)表示的是以\(i\)開頭和以\(j\)開頭的字符串的前k個字符相同。
- 分為三種情況
- 1.如果\(str[i+k]==str[j+k]\) \(k++\)。
- 2.如果\(str[i+k] > str[j+k]\) \(i = i + k + 1\),即最小表示不可能以\(str[i->i+k]\)開頭。
- 3.如果\(str[i+k] < str[j+k]\) \(j = j + k + 1\),即最小表示不可能以\(str[j->j+k]\)開頭。
- 那麽只要循環\(n\)次,就能夠判斷出字符串的最小表示是以哪個字符開頭。
- 為什麽當\(str[i+k] > str[j+k]\),\(i=i+k+1\),最小表示不可能以\(str[i->i+k]\)開頭,讓我們來舉個栗子。
- 如下圖,當\(i=1\),\(j=5\),\(k=3\)時,\(str[i+k] > str[j+k]\)。
- 首先有\(S1S2S3 == S5S6S7\),\(S4 > S8\)。
- 那麽以字符\(S2\)開頭肯定不如以字符\(S6\)開頭更優,因為\(S4 > S8\)啊。
莫隊
- 太熱了不寫了。
noip級別模板小復習