一.基础算法
贪心
二分
整数域上的二分
分治
倍增
搜索
离散化
离散化区间
二.字符串基础
三.dp(没有固定模板,但以下的主干部分基本相同)
区间dp
数位dp
单调队列优化dp
四.图论
拓扑排序
欧拉回路
最小生成树(kruskal/prim)
kruskal
1 //09/09/19 14:25 kruskal复习 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #define ll long long 7 using namespace std; 8 9 template <typename T> void in(T &x) { 10 x = 0; T f = 1; char ch = getchar(); 11 while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} 12 while(isdigit(ch)) {x = 10*x+ch-'0'; ch = getchar();} 13 x *= f; 14 } 15 16 template <typename T> void out(T x) { 17 if(x < 0) putchar('-'),x = -x; 18 if(x > 9) out(x/10); 19 putchar(x%10+'0'); 20 } 21 //--------------------------------------------------------------- 22 23 const int N = 5005,M = 200005; 24 25 int n,m,s,ans; 26 int fa[N]; 27 28 struct edge { 29 int u,v,w; 30 bool operator < (const edge &sed) const { 31 return w < sed.w; 32 } 33 }e[M]; 34 35 int find(int x) { 36 return fa[x] == x ? x : fa[x] = find(fa[x]); 37 } 38 39 int main() { 40 int i; in(n); in(m); 41 for(i = 1;i <= m; ++i) { 42 in(e[i].u); in(e[i].v); in(e[i].w); 43 } 44 sort(e+1,e+m+1); 45 for(i = 1;i <= n; ++i) fa[i] = i; 46 int cnt = 0; 47 for(i = 1;i <= m; ++i) { 48 int x = find(e[i].u),y = find(e[i].v); 49 if(x == y) continue; 50 ++cnt; fa[x] = y; ans += e[i].w; 51 if(cnt == n-1) break; 52 } 53 if(cnt == n-1) out(ans); 54 else printf("orz"); 55 return 0; 56 }
prim
1 //09/09/19 14:25 kruskal复习 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <queue> 7 #define ll long long 8 using namespace std; 9 10 template <typename T> void in(T &x) { 11 x = 0; T f = 1; char ch = getchar(); 12 while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} 13 while(isdigit(ch)) {x = 10*x+ch-'0'; ch = getchar();} 14 x *= f; 15 } 16 17 template <typename T> void out(T x) { 18 if(x < 0) putchar('-'),x = -x; 19 if(x > 9) out(x/10); 20 putchar(x%10+'0'); 21 } 22 //--------------------------------------------------------------- 23 24 const int N = 5005,M = 200005; 25 26 int n,m,ans; 27 int dis[N],vis[N]; 28 29 struct edge { 30 int v,w,nxt; 31 edge(int v = 0,int w = 0,int nxt = 0):v(v),w(w),nxt(nxt){}; 32 }e[M<<1]; int head[N],e_cnt; 33 34 void add(int u,int v,int w) { 35 e[++e_cnt] = edge(v,w,head[u]); head[u] = e_cnt; 36 } 37 38 struct node { 39 int pos,dis; 40 node(int pos = 0,int dis = 0):pos(pos),dis(dis){}; 41 bool operator < (const node &sed) const { 42 return dis > sed.dis;//debug 优先队列默认是大根堆 43 } 44 }; 45 46 priority_queue <node> q; 47 48 void prim() {//贪点 49 memset(dis,0x3f,sizeof(dis)); 50 q.push(node(1,0)); dis[1] = 0; int cnt = 0;//debug 此处cnt为已加入树中的点数(不同于kruskal的贪边) 51 while(!q.empty()) { 52 node _u = q.top(); q.pop(); 53 int u = _u.pos; 54 if(vis[u]) continue; vis[u] = 1; 55 ++cnt; ans += _u.dis; 56 if(cnt == n) break;//注意 57 for(int i = head[u]; i;i = e[i].nxt) { 58 int v = e[i].v; 59 if(dis[v] > e[i].w) { 60 dis[v] = e[i].w; q.push(node(v,dis[v])); 61 } 62 } 63 } 64 if(cnt == n) out(ans); 65 else printf("orz"); 66 }//prim 的写法与dijkstra如出一辙 主要区别在于dijkstra的dis代表到源点的最短距离,而prim的dis代表未加入树集的点到树集(连通块)的最小距离 67 //本质上都是贪心 68 69 int main() { 70 int i,u,v,w; in(n); in(m); 71 for(i = 1;i <= m; ++i) { 72 in(u); in(v); in(w); 73 add(u,v,w); add(v,u,w); 74 } 75 prim(); 76 return 0; 77 }
最短路(spfa/dijkstra/floyd)
spfa(slf优化)
1 //09/09/19 15:21 spfa(slf优化)复习 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <queue> 7 #define ll long long 8 using namespace std; 9 10 template <typename T> void in(T &x) { 11 x = 0; T f = 1; char ch = getchar(); 12 while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} 13 while(isdigit(ch)) {x = 10*x+ch-'0'; ch = getchar();} 14 x *= f; 15 } 16 17 template <typename T> void out(T x) { 18 if(x < 0) putchar('-'),x = -x; 19 if(x > 9) out(x/10); 20 putchar(x%10+'0'); 21 } 22 //--------------------------------------------------------------- 23 24 const int N = 10007,M = 500007; 25 26 int n,m,s; 27 28 struct edge { 29 int v,w,nxt; 30 edge(int v = 0,int w = 0,int nxt = 0):v(v),w(w),nxt(nxt){}; 31 }e[M]; int head[N],e_cnt; 32 33 void add(int u,int v,int w) { 34 e[++e_cnt] = edge(v,w,head[u]); head[u] = e_cnt; 35 } 36 37 int dis[N],inque[N]; 38 deque <int> q; 39 40 void spfa() { 41 memset(dis,0x3f,sizeof(dis)); 42 q.push_back(s); dis[s] = 0; inque[s] = 1; 43 while(!q.empty()) { 44 int u = q.front(); q.pop_front(); inque[u] = 0;//易错未写 inque[u] = 0 45 for(int i = head[u]; i;i = e[i].nxt) { 46 int v = e[i].v; 47 if(dis[v] > dis[u]+e[i].w) { 48 dis[v] = dis[u]+e[i].w; 49 if(!inque[v]) { 50 if(!q.empty() && dis[v] < dis[q.front()]) q.push_front(v);//易错未写 q.empty 51 else q.push_back(v); 52 inque[v] = 1; 53 } 54 } 55 } 56 } 57 for(int i = 1;i <= n; ++i) { 58 if(dis[i] != 0x3f3f3f3f) out(dis[i]); 59 else out((1<<31)-1); 60 putchar(' '); 61 } 62 } 63 64 int main() { 65 int i,u,v,w; in(n); in(m); in(s); 66 for(i = 1; i <= m; ++i) { 67 in(u); in(v); in(w); add(u,v,w); 68 } 69 spfa(); 70 return 0; 71 }
dijkstra(堆优化)
1 //09/09/19 15:39 dijkstra(堆优化)复习 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <queue> 7 #define ll long long 8 using namespace std; 9 10 template <typename T> void in(T &x) { 11 x = 0; T f = 1; char ch = getchar(); 12 while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} 13 while(isdigit(ch)) {x = 10*x+ch-'0'; ch = getchar();} 14 x *= f; 15 } 16 17 template <typename T> void out(T x) { 18 if(x < 0) putchar('-'),x = -x; 19 if(x > 9) out(x/10); 20 putchar(x%10+'0'); 21 } 22 //--------------------------------------------------------------- 23 24 const int N = 100007,M = 200007; 25 26 int n,m,s; 27 28 struct edge { 29 int v,w,nxt; 30 edge(int v = 0,int w = 0,int nxt = 0):v(v),w(w),nxt(nxt){}; 31 }e[M]; int head[N],e_cnt; 32 33 void add(int u,int v,int w) { 34 e[++e_cnt] = edge(v,w,head[u]); head[u] = e_cnt; 35 } 36 37 ll dis[N]; 38 bool vis[N]; 39 40 struct node { 41 int pos; ll dis; 42 node(int pos = 0,ll dis = 0):pos(pos),dis(dis){}; 43 bool operator < (const node &sed) const { 44 return dis > sed.dis;//debug 又写反了 45 } 46 }; 47 48 priority_queue <node> q; 49 50 void dijkstra() { 51 memset(dis,0x7f,sizeof(dis)); 52 q.push(node(s,0)); dis[s] = 0; //vis[s] = 1; 53 while(!q.empty()) { 54 node _u = q.top(); q.pop(); 55 int u = _u.pos; 56 if(vis[u]) continue; vis[u] = 1; 57 for(int i = head[u]; i;i = e[i].nxt) { 58 int v = e[i].v; 59 if(dis[v] > dis[u]+e[i].w) { 60 dis[v] = dis[u]+e[i].w; 61 //if(vis[v]) continue; 62 q.push(node(v,dis[v])); 63 //vis[v] = 1; 64 } 65 } 66 } 67 for(int i = 1;i <= n; ++i) out(dis[i]),putchar(' '); 68 } 69 70 int main() { 71 int i,u,v,w; in(n); in(m); in(s); 72 for(i = 1; i <= m; ++i) { 73 in(u); in(v); in(w); add(u,v,w); 74 } 75 dijkstra(); 76 return 0; 77 }
*有向图中,单汇最短可以通过建反图的方式转化为单源最短(P1629,P1342)
floyd
多源最短路
传递闭包
求最小环(输出方案)
差分约束系统
(强连通分量)缩点
割点/桥
点/边双连通分量
二分图
二分图最大匹配
二分图完美匹配
二分图带权匹配
*网络流
最大流
最小费用流
五.数据结构(数据处理)
前缀和
RMQ
差分/二维差分
树状数组
线段树
平衡树(splay)
六.树
树的前/中/后序遍历
树的直径
树的重心
lca(倍增求lca/树链剖分求lca)
树上差分(边差分/点差分)
树链剖分
1 //09/09/19 08:55 树剖复习 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #define ll long long 7 using namespace std; 8 9 template <typename T> void in(T &x) { 10 x = 0; T f = 1; char ch = getchar(); 11 while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} 12 while(isdigit(ch)) {x = 10*x+ch-'0'; ch = getchar();} 13 x *= f; 14 } 15 16 template <typename T> void out(T x) { 17 if(x < 0) putchar('-'),x = -x; 18 if(x > 9) out(x/10); 19 putchar(x%10+'0'); 20 } 21 //--------------------------------------------------------------- 22 23 const int N = 1e5+7; 24 25 int n,m,r,p,a[N]; 26 27 struct edge { 28 int v,nxt; 29 edge(int v = 0,int nxt = 0):v(v),nxt(nxt){}; 30 }e[N<<1]; int head[N],e_cnt; 31 32 void add(int u,int v) { 33 e[++e_cnt] = edge(v,head[u]); head[u] = e_cnt; 34 } 35 //--------------------------------------------------------------- 36 //init 37 //pre_dfs1 38 int fa[N],dep[N],sz[N],son[N]; 39 void dfs1(int u) { 40 dep[u] = dep[fa[u]]+1; sz[u] = 1; int maxs = 0; 41 for(int i = head[u]; i;i = e[i].nxt) { 42 int v = e[i].v; if(v == fa[u]) continue; 43 fa[v] = u; dfs1(v); sz[u] += sz[v];//debug not wt sz[u] += sz[v] 44 if(sz[v] > maxs) maxs = sz[v],son[u] = v; 45 } 46 } 47 //pre_dfs2 48 int top[N],id[N],w[N],cnt; 49 void dfs2(int u,int ctop) { 50 top[u] = ctop; id[u] = ++cnt; w[id[u]] = a[u]; 51 if(son[u]) dfs2(son[u],ctop); 52 for(int i = head[u]; i;i = e[i].nxt) { 53 int v = e[i].v; if(v == fa[u] || v == son[u]) continue; dfs2(v,v); 54 } 55 } 56 //--------------------------------------------------------------- 57 //segment tree 58 ll sum[N<<2],lazy[N<<2]; 59 60 void P_dn(int u,int l,int r) { 61 if(!lazy[u]) return; 62 int mid = (l+r)>>1; 63 sum[u<<1] = (sum[u<<1]+(lazy[u]*(mid-l+1))%p)%p; lazy[u<<1] = (lazy[u<<1]+lazy[u])%p; 64 sum[u<<1|1] = (sum[u<<1|1]+(lazy[u]*(r-mid))%p)%p; lazy[u<<1|1] = (lazy[u<<1|1]+lazy[u])%p; 65 lazy[u] = 0; 66 } 67 68 void Build(int u,int l,int r) { 69 if(l == r) {sum[u] = w[l]; return;} 70 int mid = (l+r)>>1; 71 Build(u<<1,l,mid); Build(u<<1|1,mid+1,r); 72 sum[u] = (sum[u<<1]+sum[u<<1|1])%p; 73 } 74 75 void A(int u,int l,int r,int x,int y,ll k) { 76 if(x <= l && y >= r) {sum[u] = (sum[u]+(k*(r-l+1))%p)%p; lazy[u] = (lazy[u]+k)%p; return;} 77 P_dn(u,l,r); int mid = (l+r)>>1; 78 if(x <= mid) A(u<<1,l,mid,x,y,k); if(y > mid) A(u<<1|1,mid+1,r,x,y,k); 79 sum[u] = (sum[u<<1]+sum[u<<1|1])%p; 80 } 81 82 ll Q(int u,int l,int r,int x,int y) { 83 if(x <= l && y >= r) return sum[u]; 84 P_dn(u,l,r); int mid = (l+r)>>1; ll res = 0;//debug 线段树基础不扎实,返回值应用long long 85 if(x <= mid) res = (res+Q(u<<1,l,mid,x,y))%p; if(y > mid) res = (res+Q(u<<1|1,mid+1,r,x,y))%p;//debug 第二个忘记%p 30pts -> 100pts 86 return res; 87 } 88 //--------------------------------------------------------------- 89 //chain 90 91 void modify(int x,int y,int z) { 92 while(top[x] != top[y]) {//不在一条重链上 93 if(dep[top[x]] < dep[top[y]]) swap(x,y);//每次让深的跳 94 //A(1,1,n,top[x],x,z); x = top[x];//WA 95 A(1,1,n,id[top[x]],id[x],z); 96 x = fa[top[x]];//易错1不加id //易错2 不写 x = fa[top[x]] //易错3不加fa 97 } 98 if(dep[x] < dep[y]) swap(x,y); 99 A(1,1,n,id[y],id[x],z); 100 } 101 102 ll query(int x,int y) { 103 ll res = 0; 104 while(top[x] != top[y]) { 105 if(dep[top[x]] < dep[top[y]]) swap(x,y); 106 res = (res+Q(1,1,n,id[top[x]],id[x]))%p; 107 x = fa[top[x]]; 108 } 109 if(dep[x] < dep[y]) swap(x,y); 110 return res = (res+Q(1,1,n,id[y],id[x]))%p; 111 } 112 113 114 int main() { 115 // freopen("0.in","r",stdin); 116 int i,x,y,z,op; in(n); in(m); in(r); in(p); 117 for(i = 1;i <= n; ++i) in(a[i]); 118 for(i = 1;i < n; ++i) { 119 in(x); in(y); add(x,y); add(y,x); 120 } 121 dfs1(r); dfs2(r,r); Build(1,1,n); 122 while(m--) { 123 in(op); in(x); 124 if(op == 1) { 125 in(y); in(z); modify(x,y,z%p); 126 }//1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 127 else if(op == 2) { 128 in(y); out(query(x,y)),putchar(' '); 129 }//2 x y 表示求树从x到y结点最短路径上所有节点的值之和 130 else if(op == 3) { 131 in(z); A(1,1,n,id[x],id[x]+sz[x]-1,z%p); 132 }//3 x z 表示将以x为根节点的子树内所有节点值都加上z 133 else { 134 out(Q(1,1,n,id[x],id[x]+sz[x]-1)); putchar(' '); 135 }//4 x 表示求以x为根节点的子树内所有节点值之和 136 } 137 return 0; 138 }
*点分治
七.数学基础
gcd/lcm
线性筛
快速幂
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 #include <vector> 8 #define ll long long 9 using namespace std; 10 11 template <typename T> void in(T &x) { 12 x = 0; T f = 1; char ch = getchar(); 13 while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} 14 while(isdigit(ch)) {x = 10*x+ch-'0'; ch = getchar();} 15 x *= f; 16 } 17 18 template <typename T> void out(T x) { 19 if(x < 0) putchar('-'),x = -x; 20 if(x > 9) out(x/10); 21 putchar(x%10+'0'); 22 } 23 //--------------------------------------------------------------- 24 25 ll b,p,k; 26 27 ll power(ll a,ll b,ll p) { 28 ll res = 1%p;//debug 1^0 mod 1 = 0//注意%p 29 for(;b;b >>= 1) { 30 if(b&1) res = (res*a)%p; 31 a = (a*a)%p; 32 } 33 return res; 34 } 35 36 int main() { 37 in(b); in(p); in(k); 38 printf("%lld^%lld mod %lld=%lld",b,p,k,power(b,p,k)); 39 return 0; 40 }
八.STL
九.骗分
随机化
random_shuffle
模拟退火