今天(2017.11.08)开始打板子。
一、读入输出优化
注意:数组类型和负号。
#include <cstdio> int read() { int x = 0, f = 1; char ch = getchar(); while (ch > '9' || ch < '0') ch == '-' && (f = -1), ch = getchar(); while (ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); return x * f; } void pf(int x) { // 如果x小于10,直接输出,否则先输出十位及以上部分,然后输出个位。如果是负数,先输出‘-’,再当成正数输出即可。 if (x < 0) putchar('-'), x = -x; // 递归版输出优化,听说效率玄学。 if (x > 9) pf(x / 10); putchar(x % 10 + '0'); } int main() { int a = read(); pf(a); }
二、并查集
模板:
#include <cstdio> const int MAXN = 5000 + 7; int dad[MAXN], n, m, p; /******************只有这两行******************************************************/ int getdad(int x) { return x == dad[x] ? x : getdad(dad[x]); } void join(int x, int y) { int a = getdad(x), b = getdad(y); if (a != b) dad[a] = getdad(b); }
/*******************是主代码。*****************************************************/
int main() { scanf("%d%d%d", &n, &m, &p); for (int i = 1; i <= n; i++) dad[i] = i; for (int i = 1, x, y; i <= m; i++) scanf("%d%d", &x, &y), join(x, y); for (int i = 1, x, y; i <= p; i++) { scanf("%d%d", &x, &y); int a = getdad(x), b = getdad(y); puts(a == b ? "Yes " : "No "); } return 0; }
三、树状数组与线段树
树状数组:http://blog.csdn.net/qq_21841245/article/details/43956633
biu
树状数组针对的是加上某值,如果是“改为某值”,则操作时加上的是(要改的值-原本的值)。
#include <cstdio> const int MAXN = 1e5 + 7; int n, m; struct Node { int tree[MAXN]; void add(int x, int v) { // 单点更新 while (x <= n) { tree[x] += v; x += x & (-x); } } int sum(int k) { // 区间求和 int ans = 0; while (k) { ans += tree[k]; k -= k & (-k); } return ans; } } T; int main() { scanf("%d", &n); for (int i = 1, v; i <= n; i++) { scanf("%d", &v); T.add(i, v); } scanf("%d", &m); for (int i = 1; i <= m; i++) { int x, a, b; scanf("%d%d%d", &x, &a, &b); if (x == 1) T.add(a, b); else printf("%d ", T.sum(b) - T.sum(a - 1)); } return 0; }
四、Kruskal
#include <cstdio> #include <algorithm> const int MAXN = 107 * 3; int n, m, cnt, dad[MAXN], size[MAXN], ans; struct Edge { int from, to, pow; bool operator<(const Edge p) const { return pow < p.pow; } } edge[MAXN]; int get(int x) { return dad[x] == x ? x : get(dad[x]); } void join(int x, int y) { int a = get(x), b = get(y); if (size[a] < size[b]) dad[a] = b, size[b] += size[a]; else dad[b] = a, size[a] += size[b]; } int main() { while (scanf("%d%d", &n ,&m) == 2) { ans = 0; if (n == 0) break; for (int i = 1; i <= m; i++) dad[i] = i, size[i] = 1; for (int i = 1; i <= n; i++) { int x, y, z; scanf("%d%d%d", &x, &y, &z); edge[i].from = x; edge[i].pow = z; edge[i].to = y; } std::sort(edge + 1, edge + n + 1); int cnt = 0; for (int i = 1; i <= n; i++) { int f = edge[i].from, t = edge[i].to; if (get(f) != get(t)) { join(f, t); cnt++; ans += edge[i].pow; } } if (cnt < m - 1) printf("? "); else printf("%d ", ans); } return 0; }
五、归并排序
应用:求逆序对
#include <iostream> #include <cstdio> const int MAXN = 100050; int n, a[MAXN], l[MAXN]; long long count; void M(int s, int mid , int e) { int i = s, j = mid + 1, k = 1; while (i <= mid && j <= e) { if (a[i] <= a[j]) l[k++] = a[i++]; else l[k++] = a[j++], count += mid + 1 - i; // 求逆序对数关键操作 } while (i <= mid) l[k++] = a[i++]; while (j <= e) l[k++] = a[j++]; for (int i = 1, j = s; j <= e; j++, i++) a[j] = l[i]; // !! } void MS(int s, int e) { if (!(e - s)) return ; else { int mid = (e + s) / 2; MS(s, mid); MS(mid + 1, e); M(s, mid, e); } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); MS(1, n); printf("%lld ", count); for (int i = 1; i <= n; i++) printf("%d ", a[i]); return 0; }
六、生无可恋的线段树
#include <cstdio> #include <algorithm> const int MAXN = 1e5 + 7; int n, m; struct Node { int tag, pow, l, r; Node *lc, *rc; Node () {} Node (int l, int r, Node *lc, Node *rc) : tag(0), pow(0), l(l), r(r), lc(lc), rc(rc) {} } *cur, *root, node[MAXN * 4]; Node *Build(int l, int r) { int mid = l + ((r - l)>> 1); return l == r ? new (cur++)Node(l, r, NULL, NULL) : new (cur++)Node(l, r, Build(l, mid), Build(mid + 1, r)); } void Cover(Node *v, int delta) { v->pow += (v->r - v->l + 1) * delta; v->tag += delta; } void PushDown(Node *v) { if (v->tag) Cover(v->lc, v->tag), Cover(v->rc, v->tag), v->tag = 0; } void Update(Node *v, int l, int r, int delta) { if (v->r < l || v->l > r) return ; else if (l <= v->l && r >= v->r) Cover(v, delta); else PushDown(v), Update(v->lc, l, r, delta), Update(v->rc, l, r, delta), v->pow = v->lc->pow + v->rc->pow; } int Q(Node *v, int l, int r) { if (v->r < l || v->l > r) return 0; else if (l <= v->l && r >= v->r) return v->pow; else return PushDown(v), Q(v->lc, l, r) + Q(v->rc, l, r); } int main() { cur = node; scanf("%d", &n); root = Build(1, n); for (int i = 1, v; i <=n; i++) scanf("%d", &v), Update(root, i, i, v); scanf("%d", &m); for (int i = 1; i <= m; i++) { int z, x, y; scanf("%d%d%d", &z, &x, &y); if (z == 1) Update(root, x, x, y); else printf("%d ", Q(root, x, y)); } return 0; }
每次写线段树总会出点错... ...
这次份的:
① 不加 #include <algorithm> 调了一个下午才发现... ...
后果:
② Q(){} 函数最后那种情况没写 ‘+’。
③ 每次写都犯的:
Update 和 Q 里第二种情况是
当前节点代表的区间被要进行操作的区间包含
而不是 要进行操作的区间被当前节点代表的区间包含。
七、二分
#include <cstdio> const int MAXN = 5e4 + 7; int s, n, m, a[MAXN]; int check(int x) { int last = 0, re = 0; for (int i = 1; i <= n + 1; i++) if (a[i] - last < x) re++; else last = a[i]; return re; } int main() { scanf("%d%d%d", &s, &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); a[n + 1] = s; int l = 1, r = s, ans = 0; while (l <= r) { int mid = (l + r) >> 1; int f = check(mid); // printf("when mid = %d, f = %d ", mid, f); if (f <= m) l = mid + 1, ans = mid; else r = mid - 1; } printf("%d ", ans); return 0; }