蒟蒻 AstralNahida 的码风
第零部 · 写在前面的碎碎念
第一章 · 前言
这里是蒟蒻 OIer AstralNahida 在 OI 中的码风的详细介绍。
个人认为码风相当清晰,供给各位参考。
第二章 · 约定
对于一些表示必要性的关键词,从 must 到 mustn't 排序如下:
必须 > 尽量 > 应当 > 建议 > 可以 > 不建议 > 不应当 > 尽量不 > 不得。
为方便阅读,本文中所有上述关键词都用粗体字表示。
另外,若没有「至少」、「至多」等词的限定,所有的数字默认为严格的。
例如「中间有一个空行」中的「有一个」默认为「有且仅有一个」。
第一部 · 整体
这里贴一份本人做洛谷 P1253 的代码:
#include <iostream>
typedef long long ll;
const ll INF = 1e18, N = 1e6 + 5;
ll a[N], w[N * 4];
ll tagReset[N * 4], tagAdd[N * 4];
inline void PushUp(int u) {
w[u] = std::max(w[u * 2], w[u * 2 + 1]);
}
void Build(int u, int l, int r) {
tagReset[u] = INF;
if (l == r) {
w[u] = a[l];
return;
}
int mid = (l + r) / 2;
Build(u * 2, l, mid);
Build(u * 2 + 1, mid + 1, r);
PushUp(u);
}
inline bool InRange(int l, int r, int ql, int qr) {
return (ql <= l) && (r <= qr);
}
inline bool OutofRange(int l, int r, int ql, int qr) {
return (r < ql) || (qr < l);
}
void MakeTag(int u, ll x, int type) {
if (type == 1) {
tagAdd[u] = 0;
tagReset[u] = x;
w[u] = x;
} else {
if (tagReset[u] == INF) {
tagAdd[u] += x;
} else {
tagReset[u] += x;
}
w[u] += x;
}
}
void PushDown(int u) {
if (tagReset[u] != INF) {
MakeTag(u * 2, tagReset[u], 1);
MakeTag(u * 2 + 1, tagReset[u], 1);
tagReset[u] = INF;
} else if (tagAdd[u]) {
MakeTag(u * 2, tagAdd[u], 2);
MakeTag(u * 2 + 1, tagAdd[u], 2);
tagAdd[u] = 0;
}
}
ll GetRangeMax(int u, int l, int r, int ql, int qr) {
if (InRange(l, r, ql, qr)) {
return w[u];
} else if (!OutofRange(l, r, ql, qr)) {
int mid = (l + r) / 2;
PushDown(u);
return std::max(GetRangeMax(u * 2, l, mid, ql, qr), GetRangeMax(u * 2 + 1, mid + 1, r, ql, qr));
} else {
return -INF;
}
}
void Update(int u, int l, int r, int ql, int qr, int x, int type) {
if (InRange(l, r, ql, qr)) {
MakeTag(u, x, type);
} else if (!OutofRange(l, r, ql, qr)) {
int mid = (l + r) / 2;
PushDown(u);
Update(u * 2, l, mid, ql, qr, x, type);
Update(u * 2 + 1, mid + 1, r, ql, qr, x, type);
PushUp(u);
}
}
int main(void) {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, q;
std::cin >> n >> q;
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
}
Build(1, 1, n);
for (int i = 1, opt, l, r, x; i <= q; i++) {
std::cin >> opt >> l >> r;
if (opt != 3) {
std::cin >> x;
Update(1, 1, n, l, r, x, opt);
} else {
std::cout << GetRangeMax(1, 1, n, l, r) << '\n';
}
}
return 0;
}
大概是这样式的。
由此可以看出,我的代码大致分为四个部分:
#include
部分,用于包含代码所需的头文件;#define
、typedef
、using
部分,用于造一些简化代码的小东西;- 全局变量、常量及函数的声明及定义部分;
- 主函数部分。
这一部只是提供代码的整体观感而已,码风具体规则详见下文。
第二部 · 头文件包含及宏定义
第一章 · 头文件
对于任意项目,在写代码的时候不得使用万能头 <bits/stdc++.h>
。除了刷题的时候可以少点时间,其它全是缺点。
对于引用的头文件,C 标准的头文件应当使用以 c
为前缀的形式,而非 .h
为后缀的形式。
例如,<string.h>
应当写成 <cstring>
。
对于所有头文件,建议将 C 标准的头文件放在一起,后必须接一个空行再把 C++ 的头文件包含进来。
另外,也建议以头文件的作用将包含的头文件分类,每个类别中间必须由一个空行分割。
上述两种分段方式任选其一即可。
另外,不得使用 using namespace std;
,否则函数名、变量名容易出现冲突。
必要时,可以使用 using std::sort;
此类方法,但仍需要确定函数名、变量名不出现冲突。
第二章 · 宏定义
对于任意宏定义,其作用为下列两种的任意一种:①简化代码或定义常量;②满足自己的小癖好。
如果一份代码中同时出现了这两种宏定义,则需要把两种宏定义分别放在一起,中间必须由一个空行分隔。
第三部 · 缩进及大括号
第一章 · 缩进
必须使用 4 空格缩进。
在每一个大括号的内部或者 case
、public
、private
等的内部,必须使用一份缩进。
对于很长的表达式,需要分行来确保可读性和可维护性时,也必须使用一份缩进。
任意 #
开头的指令之前不得使用缩进,无论它是否在原本需要使用缩进的块内。
第二章 · 大括号
大括号的常用风格有以下两种:
- 「通透」风格:
if (1 + 1 == 2)
{
break;
}
- 「紧凑」风格:
if (1 + 1 == 2) {
break;
}
必须使用这两种中的任意一种,且不得混用。
这里更建议使用第二种,否则若内部的语句很少,整个代码观感就比较空虚。
第四部 · 空格及空行
第一章 · 空格
必须妥善利用空格,否则代码过于紧凑(说难听点,挤成一坨),影响观感和可读性、可维护性。
以下列出的位置必须使用一个空格:
- 双目运算符的左右两侧(特殊地,
+
和-
作为正负号时,与后接的表达式之间不得使用空格); - 流运算符的左右两侧;
if
系列、while
和do-while
、switch
、for
和foreach
等与后接的(或前导的)大括号或小括号之间;- 一对大括号在同一行时,左大括号的后面和右大括号的前面;
- 三目运算符中,
?
和:
的左右两侧; *
表示指针类型时,若后接变量名,与变量名之间;#include
与后接的<>
之间;- 使用「饱满」风格的大括号时,左大括号与前导内容之间;
,
或;
与后接的表达式之间;- 其它必须使用空格的地方。
任何除了作为缩进以外的地方,都不得出现几个空格连用的情况。
以下列出的位置不得使用空格:
::
、->
、.
的左右两侧;*
表示指针所引用的内容时,与后接变量名之间;*
表示指针类型时,与前导的类型名之间;- 函数名与后接小括号之间;
,
或;
的左侧;- 单目运算符与参与运算的表达式之间;
+
和-
作为正负号时,与后接的表达式之间;- 其它不得使用空格的地方。
第二章 · 空行
必须妥善利用空行,否则代码过于紧凑(说难听点,挤成一坨),影响观感和可读性、可维护性。
在第一部中提到,代码大致分成四个部分,其中每个部分之间必须使用一个空行。
在其它的任何位置,应当根据代码内容合理地使用一个空行进行分隔,确保代码可读性、可维护性。
第五部 · 变量、常量及函数
第一章 · 定义
若非必要,尽量不定义全局变量。
定义常量,必须使用 #define
或 const
中的任意一种,不得混用。
其它函数必须在主函数之前声明并定义。
第二章 · 命名
命名尽量不过长,否则使用没有自动补全的编辑器时容易累死,表达式也容易过长,影响观感和可读性、可维护性。
同时,命名不得使用过于简单、没有意义的名字,尽量在命名中体现出该函数的作用。题目所给出的变量名除外。
需要注意的是,「过于简单、没有意义」的核心是「没有意义」,若单个字母有明显意义的,不算作不规范命名,如 for
中的 i
、表示顶点的 u
、v
等。
当然,变量较多时,确实不建议使用单个字母命名。
第 \(\inf\) 部 · 写在后面的碎碎念
第一章 · 后记
差不多就是这样了。我这里给出的码风规范其实是相对宽松的,有很多自由的空间。
有些人可能会问,码风真的有这么重要吗?
当然有的。上面我也提到了不少次,养成好的码风究其根本是为了保证代码的可读性和可维护性,同时保证代码美观。
好的码风对于 OIer 来说无疑是极其重要的,正所谓「码如其人」,如果你是一个有追求的 OIer,那么你应当拥有一个整洁、统一的码风。
当然,如果你决定将来做程序设计工作或现在正在做程序设计工作,你也应当养成好的码风,否则项目迟早被写成屎山。
好啦,就到这里吧,祝各位热爱自己的 OI 生涯。
第二章 · 声明
本文欢迎广大 OIer 转载,同时,转载者必须注明出处并附上原文链接,谢谢配合!
若有需要补充的地方,欢迎大家指出,谢谢!
第 \(\mathrm i\) 部 · 更新记录
- 2025/04/26 14:09 本文正式告成,发布。
- 2025/04/27 17:43 微调语言描述。
- 2025/05/05 06:24 微调语言描述。
- 2025/05/05 08:55 更换第一部中的示例代码。
- 2025/05/27 21:55 将第一部中示例代码的
uF(i, a, b, x)
和dF(i, a, b, x)
的宏定义取消。 - 2025/05/27 21:58 将本随笔置顶于个人博客主页,微调语言描述,增加第 \(\inf\) 部第二章「声明」。
- 2025/07/07 10:54 微调语言描述并更换第一部中的示例代码,将来仍可能会把示例代码更换成更具代表性的代码。