今天(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;
}