[联赛前整理] 终极必备模板
吐血了,好多。
一、基础模板
① 二维前缀和
回忆方法:画个图就懂了
延伸:最大子矩阵的方法,压行。
for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { int a; scanf("%d", &a); sum[i][j] = a + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1]; } }
② 高精度
回忆方法: 先背下来再说。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 #define maxn 50001 6 7 struct BigN{ 8 int num[maxn]; 9 int length; 10 BigN(const string& x){ 11 length = x.length(); 12 for(int i=length-1,q=0; i>=0; i--,q++){ 13 num[q] = x[i] - '0'; //注意-'0' 14 } 15 } 16 BigN(){ 17 length = 0; 18 memset(num,0,sizeof(num)); 19 } 20 BigN operator +(const BigN& x){ 21 BigN res; 22 res.length = max(x.length,length); 23 for(int i=0;i<res.length;i++){ 24 res.num[i] += x.num[i] + num[i]; 25 res.num[i+1] += res.num[i]/10; 26 res.num[i]%=10; 27 } 28 if(res.num[res.length]!=0)res.length++; 29 return res; 30 } 31 void pushdown(){ 32 int p=0; 33 for(int i=length;i>=0;i--){ 34 if(num[i]!=0){ 35 p=i; 36 break; 37 } 38 } 39 length=p+1; 40 } 41 BigN operator - (const BigN& x){ 42 BigN res; 43 res.length = max(length, x.length); 44 for(int i=0;i<res.length;i++){ 45 res.num[i] += (num[i] - x.num[i]); 46 if(res.num[i]<0) 47 { 48 res.num[i+1]-=1; 49 res.num[i]+=10; 50 } 51 } 52 res.pushdown(); 53 return res; 54 } 55 void pushup(){ 56 for(int i=0;i<length;i++){ 57 if(num[i]>9){ 58 num[i+1] += num[i]/10; 59 num[i]%=10; 60 } 61 } 62 } 63 BigN operator * (const BigN& x){ 64 BigN res; 65 res.length = length + x.length; 66 for(int i=0;i<length;i++){ 67 for(int j=0;j<x.length;j++){ 68 res.num[i+j] += num[i]*x.num[j]; 69 } 70 } 71 res.pushup(); 72 res.pushdown(); 73 return res; 74 } 75 BigN operator * (const int& x){ 76 BigN res; 77 res.length = length+10; 78 for(int i=0;i<length;i++){ 79 res.num[i] += num[i]*x; 80 } 81 res.pushup(); 82 res.pushdown(); 83 return res; 84 } 85 BigN operator / (const int& x){ 86 BigN res; 87 res.length = length; 88 for(int i=length-1;i>=0;i--) 89 res.num[i] = num[i]; 90 for(int i=length-1;i>=0;i--){ 91 if(i>0)res.num[i-1] += res.num[i]%x*10; 92 res.num[i] /= x; 93 } 94 res.pushdown(); 95 return res; 96 } 97 int operator % (const int& x){ 98 int res = 0; 99 for(int i=length-1;i>=0;i--){ 100 res = (res*10 + num[i])%x; 101 } 102 return res; 103 } 104 }; 105 ostream& operator<<(ostream& os,const BigN& x){ 106 for(int i=x.length-1;i>=0;i--) 107 os<<x.num[i]; 108 return os; 109 } 110 BigN pow(BigN b,int p){ 111 BigN res(string("1")); 112 while(p>0){ 113 if(p&1)res = res*b; 114 p = p>>1; 115 b = b*b; 116 } 117 return res; 118 } 119 //a*b = 最小公倍数*最大公约数 120 BigN gcd(BigN a,BigN b){ 121 //while(b^=a^=b^=a%=b); 122 while(!(b.length==0&&b.num[0]==0)){ 123 a=a%b; 124 swap(a,b); 125 } 126 return a; 127 } 128 BigN lcm(BigN a,BigN b,BigN Gcd){ 129 return a*b/Gcd; 130 } 131 132 int main(){ 133 string a,b; 134 cin>>a>>b; 135 BigN ba(a),bb(b); 136 if((a.length() == b.length() && a < b) || a.length() < b.length()) 137 { 138 printf("-"); 139 cout<<(bb - ba); 140 } 141 else 142 cout<<(ba-bb); 143 return 0; 144 }
③ 快速幂 & 取模
int pow(int a, int b) { int ans = 1, base = a; while(b != 0) { if(b & 1 != 0) ans *= base; base *= base; b >>= 1; } return ans; } int powmod(int a, int b, int c) { int ans = 1, base = a % c; while(b != 0) { if(b & 1 != 0) ans = (ans * base) % c; base = (base * base) % c; b>>=1; } return ans; }
④ 并查集
1 /* 2 */ 3 #include<iostream> 4 #include<cstdio> 5 #include<cstring> 6 using namespace std; 7 8 int n, m; 9 int par[10007]; 10 void init() 11 { 12 for(int i = 1; i <= n; i++) 13 par[i] = i; 14 } 15 int find(int x) 16 { 17 if(par[x] == x) 18 return x; 19 else 20 return par[x] = find(par[x]); 21 } 22 void merge(int x, int y) 23 { 24 int fx = find(x); 25 int fy = find(y); 26 //rank 27 if(fx == fy) 28 return; 29 else 30 par[fy] = fx; 31 } 32 bool same(int x, int y) 33 { 34 return (find(x) == find(y)); 35 } 36 int main() 37 { 38 scanf("%d%d", &n, &m); 39 init(); 40 for(int i = 1; i <= m; i++) 41 { 42 int z, x, y; 43 scanf("%d%d%d", &z, &x, &y); 44 if(z == 1) 45 merge(x, y); 46 else 47 { 48 if(same(x, y)) 49 printf("Y\n"); 50 else 51 printf("N\n"); 52 } 53 } 54 return 0; 55 }
⑤ 归并排序求逆序对
初赛GG了,复赛别栽在上面。。
s即为答案
1 void merge(int l, int m, int r) 2 { 3 int i = l; 4 int j = m + 1; 5 int k = l; 6 while(i <= m && j <= r) 7 { 8 if(a[i] > a[j]) 9 { 10 tmp[k++] = a[j++]; 11 s += m - i + 1; 12 } 13 else 14 { 15 tmp[k++] = a[i++]; 16 } 17 } 18 while(i <= m) 19 tmp[k++] = a[i++]; 20 while(j <= r) 21 tmp[k++] = a[j++]; 22 for(int p = l; p <= r; p++) 23 a[p] = tmp[p]; 24 } 25 void mergesort(int l, int r) 26 { 27 if(l < r) 28 { 29 int mid = (l + r) / 2; 30 mergesort(l, mid); 31 mergesort(mid + 1, r); 32 merge(l, mid, r); 33 } 34 }
⑥ 单调队列
luogu求m区间最小值(sliding window)
1 /* 2 */ 3 #include<iostream> 4 #include<cstdio> 5 #include<cstring> 6 using namespace std; 7 8 const int maxn = 2000007; 9 int n, m, x; 10 int head = 1, tail = 1; 11 pair <int, int> q[maxn]; 12 13 int main() 14 { 15 scanf("%d%d", &n, &m); 16 int x; 17 scanf("%d", &x); 18 printf("%d\n", 0); 19 20 q[head] = make_pair(1, x); 21 tail++; 22 23 for(int i = 2; i <= n; i++) 24 { 25 int x; 26 scanf("%d", &x); 27 if(i - q[head].first > m) 28 head++;//队列区间大于m,弹顶 29 printf("%d\n", q[head].second);//输出此时前m项最小 30 31 while(tail > head && x < q[tail - 1].second) 32 tail--; 33 34 q[tail] = make_pair(i, x); 35 tail++; 36 } 37 return 0; 38 }
二、数论模板
① 欧拉线性筛
for(int i = 2; i <= n; i++) { if(isprime[i] == 0) prime[++cnt] = i; for(int j = 1; prime[j] * i <= n; j++) { isprime[prime[j] * i] = 1; if(i % prime[j] == 0) break; } }
② 最大公约数
int gcd(int a, int b) { if(b == 0) return a; else return gcd(b, a % b); //lcm(a,b) = a * b / gcd(a,b); }
扩展欧几里得(exgcd)
int d, x, y; void exgcd(int a, int b) { if(b == 0) { d = a; x = 1; y = 0; } else { exgcd(b, a % b); int t = x; x = y; y = t - a/b*y; } }
③ 杨辉三角(组合数)
for(int i = 1; i <= maxn; i++) { c[i][0] = 1; c[i][i] = 1; } for(int i = 1; i <= maxn; i++) { for(int j = 1; j < i; j++) { c[i][j] = c[i-1][j] + c[i-1][j-1]; } }
④ 乘法逆元
⑤ 欧拉函数
⑥ 费马小定理
三、图论模板
① 图上最短路径
SPFA
1 bool spfa(int s) 2 { 3 for(int i=0;i<=n;i++){ 4 d[i]=INF; 5 cnt[i]=0; 6 } 7 d[s]=0; 8 q.push(s); 9 cnt[s]++; 10 while(!q.empty()) 11 { 12 int x=q.front();q.pop(); 13 inqueue[x]=0; 14 for(int i=0;i<g[x].size();i++) 15 { 16 int v=g[x][i].to,w=g[x][i].w; 17 if(d[v] > d[x]+w) 18 { 19 d[v]=d[x]+w; 20 q.push(v); 21 if(++cnt[v]>n)return false; //判断负环 22 } 23 } 24 } 25 return true; 26 }
Dijkstra (优先队列优化)
1 #include<iostream> 2 #include<vector> 3 #include<queue> 4 #include<functional> 5 using namespace std; 6 struct edge 7 { 8 int to,w; 9 }; 10 #define maxm 500010 11 #define maxn 10010 12 #define INF 2e9 13 typedef pair<int,int>P; 14 int n,m,s; 15 int v; 16 int d[maxn]; 17 vector <edge> g[maxn]; 18 19 void dijkstra() 20 { 21 priority_queue<P,vector<P>,greater<P> >que; 22 for(int i=1;i<=n;i++) 23 d[i]=INF; 24 d[s]=0; 25 que.push(P(0,s)); 26 while(!que.empty()) 27 { 28 P p=que.top();que.pop(); 29 int v=p.second; 30 if(d[v] < p.first)continue; 31 for(int i=0;i<g[v].size();i++) 32 { 33 edge e=g[v][i]; 34 if(d[e.to] > d[v]+e.w) 35 { 36 d[e.to]=d[v]+e.w; 37 que.push(P(d[e.to],e.to)); 38 } 39 } 40 } 41 }
Floyd (多源最短路 ) O(n3)
1 for(int k = 1; k <= n; k++) 2 { 3 for(int i = 1; i <= n; i++) 4 { 5 for(int j = 1; j <= n; j++) 6 { 7 dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); 8 } 9 } 10 }
② 最小生成树
注意细节不能漏掉,一次为了全对也不要那么快!调起来极其麻烦!
Kruskal
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int n, m, par[5007]; 7 struct node 8 { 9 int u, v, w; 10 node(int u = 0, int v = 0, int w = 0): u(u), v(v), w(w) {} 11 }edge[200007]; 12 bool cmp(node a, node b) 13 { 14 return a.w < b.w; 15 } 16 int find(int x) 17 { 18 if(par[x] == x) 19 return x; 20 else 21 return par[x] = find(par[x]); 22 } 23 int main() 24 { 25 scanf("%d%d", &n, &m); 26 for(int i = 1; i <= m; i++) 27 { 28 int u, v, w; 29 scanf("%d%d%d", &u, &v, &w); 30 edge[i] = node(u, v, w); 31 } 32 sort(edge + 1, edge + m + 1, cmp); 33 for(int i = 1; i <= n; i++) 34 par[i] = i; 35 int dis = 0; 36 int cnt = 0; 37 for(int i = 1; i <= m; i++) 38 { 39 int fu = find(edge[i].u); 40 int fv = find(edge[i].v); 41 if(fu != fv) 42 { 43 par[fu] = fv; 44 dis += edge[i].w; 45 cnt++; 46 } 47 if(cnt == n - 1) //edge is enough 48 break; 49 } 50 if(cnt != n - 1) 51 cout<<"orz"<<endl; 52 else 53 cout<<dis<<endl; 54 return 0; 55 }
Prim
应用范围很广,不用非得排序(存图有限制)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn = 200007; 6 const int inf = 2e9; 7 int top = 0; 8 struct edge 9 { 10 int v, w; 11 edge *next; 12 }pool[maxn * 4], *h[maxn * 2]; 13 void addedge(int u, int v, int w) 14 { 15 edge *p = &pool[++top]; 16 p->v = v; 17 p->w = w; 18 p->next = h[u]; 19 h[u] = p; 20 } 21 int n, m; 22 int ans = 0; 23 int dis[5007]; 24 bool vis[5007]; 25 void prim() 26 { 27 for(int i = 0; i <= n; i++) 28 dis[i] = inf; 29 dis[1] = 0; 30 int cnt = n; 31 while(cnt--) 32 { 33 int idx = 0; 34 for(int i = 1; i <= n; i++) 35 if(vis[i] == 0 && dis[i] < dis[idx]) 36 idx = i; 37 if(idx == 0) 38 { 39 ans = -1; 40 break; 41 } 42 ans += dis[idx]; 43 vis[idx] = 1; 44 for(edge *p = h[idx]; p; p = p->next) 45 { 46 int v = p->v; 47 int w = p->w; 48 if(vis[v] == 0) 49 { 50 dis[v] = min(dis[v], w); 51 } 52 } 53 54 } 55 } 56 int main() 57 { 58 scanf("%d%d", &n, &m); 59 for(int i = 1; i <= m; i++) 60 { 61 int u, v, w; 62 scanf("%d%d%d", &u, &v, &w); 63 addedge(u, v, w); 64 addedge(v, u, w); 65 } 66 prim(); 67 cout<<ans<<endl; 68 return 0; 69 }
③ 强联通分量 Tarjan
15 void tarjan(int u) { 16 dfn[u] = low[u] = ++idx;//init 17 s[top++] = u;//压栈 18 in_stack[u] = true; 19 for (int i = 0; i < edge[u].size();i++) { 20 int v = edge[u][i]; 21 if (!dfn[v]) {//未被访问过 22 tarjan(v);//continue 23 low[u] = min(low[u], low[v]); 24 } 25 else if (in_stack[v]) {//如果还在栈内 26 low[u] = min(low[u], dfn[v]); 27 } 28 } 29 int size=0; 30 if (dfn[u] == low[u]) {//如果u是强联通的根 31 do { 32 size++; 33 in_stack[s[--top]] = false;//退栈 34 } while (s[top] != u);//走完一个环返回 35 if(size != 1) 36 ans=min(ans,size); 37 } 38 }
④ 拓扑排序
⑤.1 Tarjan求版本
树上LCA, DFS维护深度、到根节点距离等
& ⑥ 树上倍增维护区间最大最小边
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 const int maxn = 30007; 7 const int inf = 2e9; 8 typedef long long ll; 9 struct edge 10 { 11 int v, w; 12 edge *next; 13 }pool[maxn * 4], *h[maxn], *qy[maxn]; 14 int n, q, r, top = 0, par[maxn]; 15 int lca[maxn], s[maxn], t[maxn], pow2[40]; 16 bool vis[maxn]; 17 void addedge(int u, int v, int w) 18 { 19 edge *p = &pool[++top]; 20 p->v = v; 21 p->w = w; 22 p->next = h[u]; 23 h[u] = p; 24 } 25 void addquery(int u, int v, int w) 26 { 27 edge *p = &pool[++top]; 28 p->v = v; 29 p->w = w; 30 p->next = qy[u]; 31 qy[u] = p; 32 } 33 int find(int x) 34 { 35 if(par[x] == x) 36 return x; 37 else 38 return par[x] = find(par[x]); 39 } 40 void tarjan(int u) 41 { 42 vis[u] = 1; 43 for(edge *p = h[u]; p; p = p->next) 44 { 45 int v = p->v; 46 if(vis[v] == 0) 47 { 48 tarjan(v); 49 par[v] = u; 50 } 51 } 52 for(edge *p = qy[u]; p; p = p->next) 53 { 54 int v = p->v; 55 int id = p->w; 56 if(vis[v] == 1) 57 { 58 lca[id] = find(v); 59 } 60 } 61 } 62 bool vv[maxn]; 63 int dep[maxn], fa[maxn], son[maxn], sze[maxn]; 64 ll dis[maxn]; 65 int par1[maxn * 4][25]; 66 int minw[maxn * 4][25]; 67 int maxw[maxn * 4][25]; 68 void dfs(int f, int u, int d) 69 { 70 vv[u] = 1; 71 dep[u] = d; 72 fa[u] = f; 73 for(edge *p = h[u]; p; p = p->next) 74 { 75 int v = p->v; 76 int w = p->w; 77 if(v == u || v == fa[u]) continue; 78 son[u]++; 79 dis[v] = dis[u] + w; 80 dfs(u, v, d + 1); 81 sze[u] += sze[v]; 82 } 83 84 } 85 86 void buildST(int u) 87 { 88 for(int i = 1; i <= 16; i++) 89 { 90 if(dep[u] <= (1<<i)) 91 break; 92 par1[u][i] = par1[par1[u][i-1]][i-1]; 93 maxw[u][i] = max(maxw[u][i-1], maxw[par1[u][i-1]][i-1]); 94 minw[u][i] = min(minw[u][i-1], minw[par1[u][i-1]][i-1]); 95 } 96 for(edge *p = h[u]; p; p = p->next) 97 { 98 int v = p->v; 99 int w = p->w; 100 if(v == u || v == fa[u]) continue; 101 par1[v][0] = u; 102 maxw[v][0] = w; 103 minw[v][0] = w; 104 buildST(v); 105 } 106 } 107 108 int findmin(int u, int lca) 109 { 110 if(u == lca) 111 return inf; 112 int jump = log2(dep[u] - dep[lca]); 113 return min(minw[u][jump], findmin(par1[u][jump], lca)); 114 } 115 116 int findmax(int u, int lca) 117 { 118 if(u == lca) 119 return 0; 120 int jump = log2(dep[u] - dep[lca]); 121 return max(maxw[u][jump], findmax(par1[u][jump], lca)); 122 } 123 124 int main() 125 { 126 //freopen("bigwater.in", "r", stdin); 127 //freopen("bigwater.out", "w", stdout); 128 scanf("%d%d%d", &n, &q, &r); 129 for(int i = 1; i <= n; i++) 130 { 131 par[i] = i; 132 sze[i] = 1; 133 } 134 for(int i = 1; i < n; i++) 135 { 136 int u, v, w; 137 scanf("%d%d%d", &u, &v, &w); 138 addedge(u, v, w); 139 addedge(v, u, w); 140 } 141 for(int i = 1; i <= q; i++) 142 { 143 scanf("%d%d", &s[i], &t[i]); 144 addquery(s[i], t[i], i); 145 addquery(t[i], s[i], i); 146 } 147 tarjan(r); 148 149 dis[r] = 0; 150 151 dfs(0, r, 1); 152 fa[r] = r; 153 154 par1[r][0] = r; 155 buildST(r); 156 157 for(int i = 1; i <= n; i++) 158 printf("%lld %d %d %d %d\n", dis[i], dep[i], fa[i], son[i], sze[i]); 159 160 for(int i = 1; i <= q; i++) 161 { 162 printf("%d ", lca[i]); 163 ll ansd = dis[s[i]] + dis[t[i]] - 2 * dis[lca[i]]; 164 int curmin = min(findmin(s[i], lca[i]), findmin(t[i], lca[i])); 165 int curmax = max(findmax(s[i], lca[i]), findmax(t[i], lca[i])); 166 printf("%lld %d %d\n", ansd, curmax, curmin); 167 } 168 return 0; 169 }
⑤.2 倍增求lca
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 const int maxn = 500000; 7 int n, m, r, top = 0; 8 9 struct node 10 { 11 int v; 12 node *next; 13 }pool[maxn * 4], *h[maxn * 2], *qy[maxn]; 14 void addedge(int u, int v) 15 { 16 node *p = &pool[++top]; 17 p->v = v; 18 p->next = h[u]; 19 h[u] = p; 20 } 21 void addquery(int u, int v) 22 { 23 node *p = &pool[++top]; 24 p->v = v; 25 p->next = qy[u]; 26 qy[u] = p; 27 } 28 29 int anc[maxn][20], maxw[maxn][20]; 30 int dep[maxn]; 31 bool vis[maxn]; 32 33 void dfs(int u) 34 { 35 vis[u] = 1; 36 for(int i = 1; i < 20; i++) 37 anc[u][i] = anc[anc[u][i-1]][i-1]; 38 for(node *p = h[u]; p; p = p->next) 39 { 40 int v = p->v; 41 if(vis[v] == 0) 42 { 43 dep[v] = dep[u] + 1; 44 anc[v][0] = u; 45 dfs(v); 46 } 47 } 48 } 49 int lca(int u, int v) 50 { 51 if(dep[u] < dep[v]) 52 swap(u, v); 53 for(int i = 19; i >= 0; i--) //移到同一深度 54 { 55 if(dep[v] <= dep[anc[u][i]]) 56 u = anc[u][i]; 57 } 58 if(u == v) // v是u的祖先 59 return u; 60 for(int i = 19; i >= 0; i--) 61 { 62 if(anc[u][i] != anc[v][i]) //从最大祖先开始判断 63 { 64 u = anc[u][i]; //不相同证明还没到 65 v = anc[v][i]; //于是继续跳 66 } 67 } 68 return anc[u][0]; 69 } 70 int main() 71 { 72 scanf("%d%d%d", &n, &m, &r); 73 for(int i = 1; i < n; i++) 74 { 75 int u, v; 76 scanf("%d%d", &u, &v); 77 addedge(u, v); 78 addedge(v, u); 79 } 80 dep[r] = 1; 81 anc[r][0] = r; 82 dfs(r); 83 for(int i = 1; i <= m; i++) 84 { 85 int a, b; 86 scanf("%d%d", &a, &b); 87 printf("%d\n", lca(a, b)); 88 } 89 return 0; 90 }