日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【学习笔记】OI模板整理

發(fā)布時間:2025/3/15 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【学习笔记】OI模板整理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

CSP2019前夕整理一下模板,順便供之后使用

1. 數(shù)據(jù)結(jié)構(gòu)

1.1. 虛樹

描述:
給定樹上的\(k\)個關(guān)鍵點,構(gòu)建出一棵虛樹,只有關(guān)鍵點和任意兩個關(guān)鍵點的LCA會被保留,且原樹上的祖先關(guān)系和虛樹上祖先關(guān)系保持一致??梢宰C明虛樹最多有\((2k-1)\)個點。
把所有關(guān)鍵點按DFS序排序,用一個棧維護動態(tài)加點連邊即可。時間復雜度\(O(k\log n)\).
注意事項:
一定要處理好最先加入棧中的點(所有點的LCA).
代碼:
addedge0_(u,v)表示在\(u\)\(v\)之間連邊,邊權(quán)根據(jù)實際情況確定。

bool cmp(int x,int y) {return dfn[x]<dfn[y];} void build() {sort(ky+1,ky+kyn+1,cmp); rt = ky[1]; for(int i=2; i<=kyn; i++) rt = LCA(rt,ky[i]).first;tp = 1; stk[tp] = rt; n0++; kid[n0] = rt; isky[ky[1]] = true;for(int i=(rt==ky[1]?2:1); i<=kyn; i++){int u = ky[i],lca = LCA(stk[tp],u).first;if(lca==stk[tp]) {tp++; stk[tp] = u; n0++; kid[n0] = u; isky[u] = true;}else{while(tp>1 && dep[stk[tp-1]]>dep[lca]) {addedge0_(stk[tp],stk[tp-1]); tp--;}addedge0_(stk[tp],lca); tp--;if(stk[tp]!=lca){tp++; stk[tp] = lca; n0++; kid[n0] = lca;}tp++; stk[tp] = u; n0++; kid[n0] = u; isky[u] = true;}}while(tp>1){addedge0_(stk[tp],stk[tp-1]);tp--;} }

1.2. 左偏樹

描述:
可并堆的一種實現(xiàn),支持插入、刪除、合并、取最小值等堆操作,單個操作時間復雜度均不超過\(O(\log n)\).
代碼:

int merge(int u,int v) {if(u==0||v==0) return u+v;if(val[u]>val[v]) swap(u,v);son[u][1] = merge(son[u][1],v);if(dis[son[u][1]]>dis[son[u][0]]) {swap(son[u][1],son[u][0]);}dis[u] = dis[son[u][1]]+1;return u; } void insert(int u,int x) {siz++; val[siz] = x;rtn[u] = merge(rtn[u],siz); } int popnode(int u) {return merge(son[u][0],son[u][1]); }

1.3. KD樹

暫無

2. 字符串

2.1. 后綴數(shù)組

描述:
倍增法求后綴數(shù)組,時間復雜度\(O(n\log n)\).
sa[i]: 排在第\(i\)位的后綴
rk[i]: 后綴\(i\)的排名
h[i]: 后綴\(i\)與其前一名的后綴的LCP。
height[i]: 第\(i\)名與其前一名的后綴的LCP.
注意:

(1) w1處不可令h[1]=1然后從\(2\)開始循環(huán)。
代碼:

namespace SA {int height[N+3],h[N+3],tmp[N+3],st[lgN+2][N+3],buc[N+3];void buildSA(){int *x = rk,*y = tmp;for(int i=1; i<=S; i++) buc[i] = 0;for(int i=1; i<=n; i++) buc[x[i]=a[i]]++;for(int i=1; i<=S; i++) buc[i] += buc[i-1];for(int i=n; i>=1; i--) sa[buc[x[i]]--] = i;int p = 0,s = S;for(int j=1; p<n; j<<=1){p = 0;for(int i=n-j+1; i<=n; i++) y[++p] = i;for(int i=1; i<=n; i++) {if(sa[i]>j) y[++p] = sa[i]-j;}for(int i=1; i<=s; i++) buc[i] = 0;for(int i=1; i<=n; i++) buc[x[y[i]]]++;for(int i=1; i<=s; i++) buc[i] += buc[i-1];for(int i=n; i>=1; i--) sa[buc[x[y[i]]]--] = y[i];p = 1; swap(x,y); x[sa[1]] = 1;for(int i=2; i<=n; i++) x[sa[i]] = y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p:++p;s = p;}for(int i=1; i<=n; i++) rk[sa[i]] = i;for(int i=1; i<=n; i++) //w1{h[i] = h[i-1]==0?0:h[i-1]-1;while(i+h[i]<=n && sa[rk[i]-1]+h[i]<=n && a[i+h[i]]==a[sa[rk[i]-1]+h[i]]) {h[i]++;}}for(int i=1; i<=n; i++) height[i] = h[sa[i]];for(int i=1; i<=n; i++) st[0][i] = height[i];for(int j=1; j<lgN; j++){for(int i=1; i+(1<<j)-1<=n; i++) {st[j][i] = min(st[j-1][i],st[j-1][i+(1<<j-1)]);}}}int querymin(int l,int r){int g = lg2[r-l+1]; int *adr = st[g];return min(adr[l],adr[r-(1<<g)+1]);}int LCP(int x,int y){if(x==y) return n-x+1; if(rk[x]>rk[y]) swap(x,y);return querymin(rk[x]+1,rk[y]);} } using SA::buildSA; using SA::LCP;

2.2. 擴展KMP

描述:
求出一個串的每個后綴與整個串的LCP. 與Manacher算法極其類似,時間復雜度\(O(n)\).
z[i]: 后綴\(i\)與母串的LCP長度。
代碼:

void Z_box() {int mx = 0,mxid = 0; z[1] = m;for(int i=2; i<=m; i++){if(a[i]!=a[1]) {z[i] = 0;}else if(i>mx) {z[i] = 1;}else {z[i] = min(z[i-mxid+1],mx-i+1);}while(i+z[i]<=m && a[i+z[i]]==a[z[i]+1]) {z[i]++;}if(i+z[i]-1>mx) {mx = i+z[i]-1; mxid = i;}} }

2.3. Manacher算法

描述:
求出以每個位置為中心的最長回文子串,時間復雜度\(O(n)\).
注意事項:

(1) 不要把\(2n+1\)寫成\(n\).
代碼:

void manacher() {for(int i=n; i>=1; i--) a[2*i] = a[i];for(int i=1; i<=2*n+1; i+=2) a[i] = '#';int mxid = 1,mx = 1; p[1] = 1;for(int i=2; i<=2*n+1; i++){if(i>mx) {p[i] = 1;}else {p[i] = min(p[2*mxid-i],mx-i+1);}while(i-p[i]>0 && i+p[i]<=2*n+1 && a[i+p[i]]==a[i-p[i]]) {p[i]++;}if(i+p[i]-1>mx) {mx = i+p[i]-1; mxid = i;}} }

2.4. 后綴自動機

描述:
增量法構(gòu)造后綴自動機,時間復雜度\(O(n)\).
注意廣義后綴自動機必須對Trie樹進行BFS建立才能保證復雜度為節(jié)點數(shù),否則復雜度退化為所有葉子節(jié)點總深度。
注意事項:

(1) 不要忘記初始化三個變量。
代碼:

void init() {siz = lstpos = rtn = 1; } void insertchar(char ch) {int p = lstpos,np; siz++; np = lstpos = siz; len[np] = len[p]+1; sz[np]++;for(; p && son[p][ch]==0; p=fa[p]) {son[p][ch] = np;}if(p==0) {fa[np] = rtn;}else{int q = son[p][ch];if(len[q]==len[p]+1) {fa[np] = q;}else{siz++; int nq = siz; len[nq] = len[p]+1;memcpy(son[nq],son[q],sizeof(son[q]));fa[nq] = fa[q]; fa[q] = fa[np] = nq;for(; p && son[p][ch]==q; p=fa[p]) {son[p][ch] = nq;}}} }

2.5. 回文自動機

描述:
一個字符串本質(zhì)不同的回文子串個數(shù)不超過\(n\). 回文自動機上一個節(jié)點代表一個回文子串。
增量法構(gòu)造回文自動機,時間復雜度\(O(n)\).
代碼:

void initPAM() {siz = 1; fail[0] = fail[1] = 1; len[0] = 0; len[1] = -1; lstpos = 1; } void insertchar(int id) {int p = lstpos;while(a[id-1-len[p]]!=a[id]) {p = fail[p];}if(!son[p][a[id]]){siz++; int u = siz,v = fail[p];while(a[id-1-len[v]]!=a[id]) {v = fail[v];}fail[u] = son[v][a[id]]; len[u] = len[p]+2; son[p][a[id]] = u;}lstpos = son[p][a[id]]; }

2.6. Lyndon分解

描述:
若一個串的最小循環(huán)表示為它本身,則稱作Lyndon串。
將一個串劃分為若干Lyndon串,稱作Lyndon劃分。一個串的Lyndon劃分方案唯一。
Lyndon劃分的Duval算法,時間復雜度\(O(n)\).
代碼:
暫無

2.7. 最小循環(huán)表示

暫無

3. 圖論

3.1. Tarjan算法

3.1.1. 強連通分量

描述:
Tarjan求有向圖的強連通分量。構(gòu)建DFS樹,統(tǒng)計每個點的DFS時間戳(dfn[u])以及其所到達的時間戳最小的點(low[u]), 若后者為該點本身,則求出一個極大強連通分量。時間復雜度\(O(n+m)\).
注意事項:
注意要從每個未遍歷的點出發(fā)進行遍歷。
代碼:

void tarjan(int u) {cnt++; dfn[u] = cnt; low[u] = cnt; ins[u] = true;tp++; sta[tp] = u;for(int i=fe0[u]; i; i=e0[i].nxt){if(!dfn[e0[i].v]) {tarjan(e0[i].v); low[u] = min(low[u],low[e0[i].v]);}else if(ins[e0[i].v]) low[u] = min(low[u],dfn[e0[i].v]);}if(low[u]==dfn[u]){num++; ca[num] = a[u];while(sta[tp]!=u){ins[sta[tp]] = false;clr[sta[tp]] = num;ca[num] += a[sta[tp]];tp--;}ins[u] = false; clr[u] = num; tp--;} }

3.1.2. 點雙連通分量

描述:
Tarjan算法求無向圖的點雙連通分量。構(gòu)建DFS樹,low[u]的定義改為該點經(jīng)過至多一條非樹邊到達的最小的時間戳,若某個點\(u\)存在至少一個兒子\(v\)滿足\(low[v]\ge dfn[u]\), 則\(u\)是割點。時間復雜度\(O(n+m)\).
點雙連通分量一定是邊雙連通分量,割邊的兩個端點一定是割點。
代碼:
(建圓方樹)

namespace Graph {const int N = 1e6;const int M = 4e6;struct Edge{int v,nxt;} e[(M<<1)+3];int fe[N+3];int fa[N+3];int dfn[N+3],low[N+3],stk[N+3];int n,en,cnt,tp;void addedge(int u,int v){en++; e[en].v = v;e[en].nxt = fe[u]; fe[u] = en;}void Tarjan(int u){cnt++; dfn[u] = low[u] = cnt;tp++; stk[tp] = u;for(int i=fe[u]; i; i=e[i].nxt){int v = e[i].v;if(v==fa[u]) continue;if(!dfn[v]){fa[v] = u; Tarjan(v);low[u] = min(low[u],low[v]);if(low[v]>=dfn[u]){Tree::n++; Tree::addedge(u,Tree::n); Tree::addedge(Tree::n,u);while(tp>0){Tree::addedge(Tree::n,stk[tp]);Tree::addedge(stk[tp],Tree::n);tp--;if(stk[tp+1]==v) {break;}}}}else {low[u] = min(low[u],dfn[v]);}}}void buildTree(){Tree::n = n;for(int i=1; i<=n; i++) Tree::a[i] = 1;for(int i=1; i<=n; i++){if(!dfn[i]) {Tarjan(i);}}} }

3.1.3. 邊雙連通分量

描述:
把點雙連通分量的\(\ge\)改成\(\gt\)即可。
代碼:
略。

3.2. 歐拉回路

3.2.1. 無向圖歐拉回路

描述:
若無向圖連通且度數(shù)為奇數(shù)的點個數(shù)不超過\(2\), 則存在歐拉回路。DFS時記錄回溯的路徑,即可構(gòu)造出一條歐拉回路,時間復雜度\(O(m)\).
注意事項:

(1) 一定要使用自殺式遍歷,否則時間復雜度退化為平方級。
代碼:

namespace Undirected {struct Edge{int v,nxt;} e[M+2];int fe[N+2];int dgr[N+2];int ans[(N<<1)+2];bool vis[M+2];int n,m,en,tp;void addedge(int u,int v){en++; e[en].v = v;e[en].nxt = fe[u]; fe[u] = en;dgr[u]++;}void dfs(int u){for(int i=fe[u]; i; i=fe[u]){fe[u] = e[i].nxt;if(vis[(i+1)>>1]) continue;vis[(i+1)>>1] = true;dfs(e[i].v);tp++; ans[tp] = (i&1) ? ((i+1)>>1) : -((i+1)>>1);}}void solve(){scanf("%d%d",&n,&m);for(int i=1; i<=m; i++){int x,y;scanf("%d%d",&x,&y);addedge(x,y);addedge(y,x);}for(int i=1; i<=n; i++){if(dgr[i]&1){printf("NO");return;}}tp = 0; dfs(e[1].v);if(tp<m) {printf("NO"); return;}printf("YES\n");for(int i=tp; i>=1; i--){printf("%d ",ans[i]);}} }

3.2.2. 有向圖歐拉回路

描述:
有向圖中每個點入度等于出度是存在歐拉回路的必要條件。依然可以通過記錄回溯路徑的方法構(gòu)造歐拉回路。時間復雜度\(O(m)\).
代碼:

namespace Directed {struct Edge{int v,nxt;} e[M+2];int fe[N+2];int ind[N+2];int oud[N+2];int ans[(N<<1)+2];bool vis[M+2];int n,m,en,tp;void addedge(int u,int v){en++; e[en].v = v;e[en].nxt = fe[u]; fe[u] = en;oud[u]++; ind[v]++;}void dfs(int u){for(int i=fe[u]; i; i=fe[u]){fe[u] = e[i].nxt;if(vis[i]) continue;vis[i] = true;dfs(e[i].v);tp++; ans[tp] = i;}}void solve(){scanf("%d%d",&n,&m); tp = 0;for(int i=1; i<=m; i++){int x,y; scanf("%d%d",&x,&y);addedge(x,y);}for(int i=1; i<=n; i++){if(ind[i]!=oud[i]) {printf("NO"); return;}}dfs(e[1].v);if(tp<m) {printf("NO"); return;}printf("YES\n");for(int i=tp; i>=1; i--) printf("%d ",ans[i]);} }

4. 數(shù)論

4.1. 擴展歐幾里得算法

描述:
求解不定方程\(ax+by=\gcd(a,b)\). 時間復雜度\(O(\log(a+b))\).
代碼:

llong exgcd(llong a,llong b,llong &x,llong &y) {if(b==0) {x = 1,y = 0; return x;}llong nx,ny; llong ret = exgcd(b,a%b,nx,ny);x = ny; y = nx-a/b*ny;return ret; }

4.2. 擴展中國剩余定理

描述:
求解同余方程組,模數(shù)可以不互質(zhì)。具體做法是將模數(shù)不互質(zhì)的方程進行合并。
代碼:
暫無

4.3. 擴展BSGS

暫無

4.4. 二次剩余之Cipolla算法

暫無

5. 多項式

暫無

與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的【学习笔记】OI模板整理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。