文档地址:https://api.guwolf.com/
备用地址:https://guwolf-api.azurewebsites.net/
已实现功能:
| 功能 |
|---|
| 获取IP |
| 获取DNS记录 |
待添加功能:
| 功能 | 状态 |
|---|
有功能建议请务必通过评论或是其他方式让我得知!!!
ヾ(≧∇≦*)ゝ
Brotli是Google在2015年推出的压缩算法,目前各大浏览器均已支持Brotli,相比Gzip,有着更高的压缩率(尤其在处理CSS、JS、HTML这类文件),解压速度却相差无几,这意味着它有着更小的数据传输量,对于网络环境较差、带宽受限的用户或移动端访问者而言,能直接转化为更快的页面加载速度和更流畅的交互体验。
所以对于弱网环境下(如跨国传输),一个可行的优化思路是优先使用Brotli,对于不支持Brotli的浏览器,再回退到Gzip。
当然,更高的压缩率比如会带来压缩时更大的CPU开销,所以我们接下来也会介绍预压缩这种解决方案来缓解这个问题。
先克隆ngx\_brotli源代码到本地
git clone始化和同步ngx\_brotli的子模块
cd ngx_brotli && git submodule update --init下载Nginx的源码并解压
wget https://nginx.org/download/nginx-1.28.0.tar.gz && tar zxvf nginx-1.28.0.tar.gz安装依赖库
apt update && apt install libbrotli-dev进入源代码目录
cd nginx-1.28.0首先查看当前的Nginx编译参数
nginx -V生成Makefile并编译
./configure [原参数] --add-module=[ngx_brotli路径]
make编译好的二进制在 objs/nginx ,先把原来的nginx二进制复制一份用于防止意外,然后替换原来的二进制文件
在http块下加入
http {
...
brotli on;
brotli_comp_level 6;
brotli_min_length 512;
brotli_types text/plain text/javascript text/css text/xml text/x-component font/opentype application/json;
brotli_static on;
...参数解释
| 指令名称 | 语法格式 | 默认值 | 作用域 | 描述 | 重要参数说明 |
|---|---|---|---|---|---|
| brotli_static | on , off , always | off | http, server, location | 启用/禁用预压缩文件(.br)检测 | -on:客户端支持Brotli时返回.br文件- always:强制返回.br文件(无论客户端是否支持) |
| brotli | on , off | off | http, server, location, if | 启用/禁用动态响应压缩 | 需与brotli_types配合使用 |
| brotli_types | [mime_type ...] , * | text/html | http, server, location | 指定启用压缩的MIME类型 | -*:压缩所有类型- text/html 始终被压缩(无需声明) |
| brotli_buffers | | - | http, server, location | 已废弃(配置会被忽略) | 历史遗留参数,无实际作用 |
| brotli_comp_level | `` | 6 | http, server, location | 设置动态压缩级别 | 范围:0-11- 0:最快(最低压缩)- 11:最慢(最高压缩) |
| brotli_window | `` | 512k | http, server, location | 设置滑动窗口大小(影响压缩率和内存) | 有效值:1k,2k,4k,8k,16k,32k,64k,128k,256k,512k,1m,2m,4m,8m,16m |
| brotli_min_length | `` | 20 | http, server, location | 设置启用压缩的最小响应长度(仅依据Content-Length头) | 单位:字节建议值:≥256(避免小文件压缩得不偿失) |
预压缩可以减少CPU开销,由于动态压缩会在每次请求(尤其是高并发下)对CPU造成压力,无论你是想优化并发性能还是想得到更高的压缩率,都建议使用Brotli预压缩,在打开了 brotli_static 项的时候nginx会先检测当前访问的文件是否有 .br 的预压缩文件并返回 (如果有的话,直接返回预压缩文件,没有的话再根据 brotli 项是否开启,决定是否进行动态压缩)。
所以我们可以写一个脚本去处理预压缩
#!/bin/bash
WEB_ROOT="/aaa/www" 网页根目录
COMP_LEVEL=11 # 压缩级别 (0-11)
LOG_FILE="/var/log/br.log" #存储日志的路径
# 创建日志目录
mkdir -p "$(dirname "$LOG_FILE")"
# 查找需要压缩的文件
find "$WEB_ROOT" -type f \( \
-name "*.html" -o \
-name "*.css" -o \
-name "*.js" -o \
-name "*.xml" -o \
-name "*.json" -o \
-name "*.svg" -o \
-name "*.ttf" -o \
-name "*.woff" -o \
-name "*.woff2" \
\) | while read -r file; do
# 跳过已压缩文件(如果源文件未修改)
if [ -f "$file.br" ] && [ "$file" -ot "$file.br" ]; then
continue
fi
# 记录压缩开始时间
start_time=$(date +%s)
# 执行压缩(修正后的命令)
brotli --quality="$COMP_LEVEL" --force --keep --output="$file.br" "$file"
# 记录压缩结果
end_time=$(date +%s)
orig_size=$(stat -c%s "$file")
comp_size=$(stat -c%s "$file.br")
ratio=$(echo "scale=2; $comp_size * 100 / $orig_size" | bc)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Compressed: $file" >> "$LOG_FILE"
echo " Original: $orig_size bytes, Compressed: $comp_size bytes, Ratio: ${ratio}%" >> "$LOG_FILE"
echo " Time taken: $((end_time - start_time)) seconds" >> "$LOG_FILE"
echo "----------------------------------------" >> "$LOG_FILE"
done
echo "Completed. Log saved to: $LOG_FILE"这样,在每次文件发生变化的时候都运行一次,我们就可以使用最高的压缩率和最小的CPU开销来响应请求了。
]]>我们可以通过CSS注入来使得浏览器加载需要的字体文件, 以JetBrains Mono为例
从JetBrains Mono官网下载字体文件,并把woff和woff2格式的字体文件放置在fonts目录,并把fonts目录移到code-server安装路径下的 lib/vscode/out/vs/code/browser/workbench 位置。
以下是目录树
/usr/lib/code-server/lib/vscode/out/vs/code/browser/workbench
├── fonts
│ ├── JetBrainsMono-Bold-Italic.woff
│ ├── JetBrainsMono-Bold-Italic.woff2
│ ├── JetBrainsMono-Bold.woff
│ ├── JetBrainsMono-Bold.woff2
│ ├── JetBrainsMono-ExtraBold-Italic.woff
│ ├── JetBrainsMono-ExtraBold-Italic.woff2
│ ├── JetBrainsMono-ExtraBold.woff
│ ├── JetBrainsMono-ExtraBold.woff2
│ ├── JetBrainsMono-Italic.woff
│ ├── JetBrainsMono-Italic.woff2
│ ├── JetBrainsMono-Medium-Italic.woff
│ ├── JetBrainsMono-Medium-Italic.woff2
│ ├── JetBrainsMono-Medium.woff
│ ├── JetBrainsMono-Medium.woff2
│ ├── JetBrainsMono-Regular.woff
│ └── JetBrainsMono-Regular.woff2新建一个 fonts.css 放在code-server安装路径下的 lib/vscode/out/vs/code/browser/workbench 位置
我的是 /usr/lib/code-server/lib/vscode/out/vs/code/browser/workbench
@font-face {
font-family: 'JetBrains Mono';
src: url('fonts/JetBrainsMono-Regular.woff2') format('woff2'),
url('fonts/JetBrainsMono-Regular.woff') format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('fonts/JetBrainsMono-Italic.woff2') format('woff2'),
url('fonts/JetBrainsMono-Italic.woff') format('woff');
font-weight: 400;
font-style: italic;
}
/* 可根据需要添加更多字重和样式 */
/*
@font-face {
font-family: 'JetBrains Mono';
src: url('fonts/JetBrainsMono-Medium.woff2') format('woff2'),
url('fonts/JetBrainsMono-Medium.woff') format('woff');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('fonts/JetBrainsMono-Medium-Italic.woff2') format('woff2'),
url('fonts/JetBrainsMono-Medium-Italic.woff') format('woff');
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('fonts/JetBrainsMono-Bold.woff2') format('woff2'),
url('fonts/JetBrainsMono-Bold.woff') format('woff');
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('fonts/JetBrainsMono-Bold-Italic.woff2') format('woff2'),
url('fonts/JetBrainsMono-Bold-Italic.woff') format('woff');
font-weight: 700;
font-style: italic;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('fonts/JetBrainsMono-ExtraBold.woff2') format('woff2'),
url('fonts/JetBrainsMono-ExtraBold.woff') format('woff');
font-weight: 800;
font-style: normal;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('fonts/JetBrainsMono-ExtraBold-Italic.woff2') format('woff2'),
url('fonts/JetBrainsMono-ExtraBold-Italic.woff') format('woff');
font-weight: 800;
font-style: italic;
} */编辑工作台 HTML 文件,在 <head> 部分添加 CSS 引用:
<link rel="stylesheet" href="{{WORKBENCH_WEB_BASE_URL}}/out/vs/code/browser/workbench/fonts.css">没有用到的字体可以不放
/usr/lib/code-server/lib/vscode/out/vs/code/browser/workbench
├── callback.html
├── fonts
│ ├── JetBrainsMono-Bold-Italic.woff
│ ├── JetBrainsMono-Bold-Italic.woff2
│ ├── JetBrainsMono-Bold.woff
│ ├── JetBrainsMono-Bold.woff2
│ ├── JetBrainsMono-ExtraBold-Italic.woff
│ ├── JetBrainsMono-ExtraBold-Italic.woff2
│ ├── JetBrainsMono-ExtraBold.woff
│ ├── JetBrainsMono-ExtraBold.woff2
│ ├── JetBrainsMono-Italic.woff
│ ├── JetBrainsMono-Italic.woff2
│ ├── JetBrainsMono-Medium-Italic.woff
│ ├── JetBrainsMono-Medium-Italic.woff2
│ ├── JetBrainsMono-Medium.woff
│ ├── JetBrainsMono-Medium.woff2
│ ├── JetBrainsMono-Regular.woff
│ └── JetBrainsMono-Regular.woff2
├── fonts.css
├── workbench.css
├── workbench.html
├── workbench.js
└── workbench.js.map修改setting.json的相关内容
{
"editor.fontFamily": "'JetBrains Mono', Consolas, 'Courier New'",
"editor.fontLigatures": true, //对于连字字体,一定要打开连字符功能
}注意: 对于连字字体,一定要打开fontLigatures 否则会出现光标错位问题

此时,我的光标所在位置应该是行末

在算法竞赛中,树状数组(Fenwick Tree)因其简洁高效的特性被广泛使用。但传统实现需要预先确定数据范围并预分配空间,当值域达到1e18量级时,离散化预处理会带来诸多不便:需要离线处理、增加编码复杂度。
我们可以利用unordered_map的无序容器特性配合树状数组的跳跃特性,实现动态内存分配的树状数组,创建出一个1e18甚至更大的树状数组,可以省去离散化的步骤,同时无需离线
#define LL long long
unordered_map<LL, LL> tree;
const LL N = 1e18 + 10;
LL lowbit(LL x) {return x & -x;}
void add(LL x, LL v) {
while(x <= N) {
tree[x] += v;
x += lowbit(x);
}
}
LL sum(LL x) {
LL sum = 0;
while(x) {
sum += tree[x];
x -= lowbit(x);
}
return sum;
}✅ 优势:
⚠️ 注意事项:
下面是使用超大树状数组做的题
1D Country - AtCoder abc371\_d - Virtual Judge

推荐在以下场景使用该技巧:
今年是2024年,2024 - 2007 = 17, 该题直接输出17就好
#include <bits/stdc++.h>
using namespace std;
int main() {
cout << 17;
return 0;
}很容易发现,要赢得比赛,笨娜娜需要赢得的回合数需要超过总回合数的一半。
#include<iostream>
using namespace std;
int main() {
int n;
cin >> n;
cout << n / 2 + 1;
return 0;
}如果该数能被 2 循环整除为 1,统计循环次数并输出。
否则输出 -1
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, cnt = 0;
cin >> n;
while(n % 2 == 0) {
n /= 2, ++cnt;
}
if (n == 1) cout << cnt;
else cout << "-1";
return 0;
}可以发现,如果 当前位置拥有的石头总数 减去 上一个位置拥有的石头总数 不等于 当前位置所收集的石头数,那么丢失的石头的位置就是当前的位置。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, la = 0, now, temp;
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> temp >> now;
if (now - la != temp) {
cout << i + 1 << endl;
break;
}
la = now;
}
return 0;
}#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
if(n > 0) cout << 2 * n - 1 << "\n";
else cout << -2 * n << "\n";
return 0;
}简单思维题,难度在于三个画布的最优摆放
尽量用完所有的画布空间最优。
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
int ans = 0;
ans += x / 15 * 4;
x %= 15;
if (x > 10) ans += 4;
else if (x > 6) ans += 3;
else if (x > 2) ans += 2;
else if (x > 0) ans += 1;
else ans += 0;
cout << ans << " ";
}
return 0;
}每次选到要搞卫生的位置时就给该位置打上flag,下次遍历数组时遇到已经打上flag的就跳过
#include <iostream>
using namespace std;
int a[51];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int n, k, j = 0;
cin >> n >> k;
for (int i = 1; i <= k; ++i) {
int cnt = 0;
while (cnt < i) {
++j;
if (j > n) j = 1;
if (!a[j] && ++cnt == i) break;
}
a[j] = 1;
}
cout << j << endl;
return 0;
}先求出每场比赛使用超级棒棒糖能多获得的分数,然后贪心的从大到小取,如果取到最后GGbond的总分仍无法大于超人强,则输出负一。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
void solve() {
int n;
LL h, k, hxy = 0; //hxy代码超人强和GGbond的分差
pair<LL, LL> a[100005];
cin >> n >> h >> k;
vector<LL> c(n);
for (int i = 0; i < n; ++i) {
cin >> a[i].first;
hxy -= a[i].first;
}
for(int i = 0; i < n; ++i) {
cin >> a[i].second;
hxy += a[i].second;
c[i] = max(h - a[i].first, a[i].second);
}
sort(c.rbegin(), c.rend());
if (hxy < 0) {
cout << "0\n";
return;
}
for (int i = 0; i < n; ++i) {
hxy -= min(k, c[i]);
if (hxy < 0) {
cout << i + 1 << endl;
return;
}
}
cout << "-1\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
solve();
return 0;
}按行输出计算结果的每个数字对应每行的字符串
#include<bits/stdc++.h>
using namespace std;
string str[] = {
"##### ....# ##### ##### #...# ##### ##### ##### ##### #####",
"#...# ....# ....# ....# #...# #.... #.... ....# #...# #...#",
"#...# ....# ....# ....# #...# #.... #.... ....# #...# #...#",
"#...# ....# ##### ##### ##### ##### ##### ....# ##### #####",
"#...# ....# #.... ....# ....# ....# #...# ....# #...# ....#",
"#...# ....# #.... ....# ....# ....# #...# ....# #...# ....#",
"##### ....# ##### ##### ....# ##### ##### ....# ##### #####"
};
int zz[] = {0, 6, 12, 18, 24, 30, 36, 42, 48, 54};
int main() {
int a, b;
cin >> a >> b;
string num = to_string(a + b);
for (auto &i: str) {
for (char &j: num) {
for (int k = zz[j - '0']; k < zz[j - '0'] + 5; ++k)
cout << i[k];
cout << ' ';
}
cout << endl;
}
return 0;
} 很容易发现,层数对应的总步数就是该层对应矩形的面积,接下来可以二分求出对应步数所在的层数
(也可以先预处理出所有的层数情况,并使用 lower_bound 查找)
根据奇偶判断从x的正负半轴开始出发,计算最终坐标。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
LL ls[800000], zz = 1, step, layer, x, y;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
// 预处理层数信息
for (; zz * (2 * zz - 1) < 1e12; ++zz)
ls[zz] = zz * (2 * zz - 1);
int q;
cin >> q;
while (q--) {
cin >> step;
layer = lower_bound(ls, ls + zz, step) - ls; // 二分查找所在层数
step -= ls[layer];
x = layer - 1;
if (layer & 1) x = -x;
step = abs(step);
if (step < layer) y = step;
else if (step <= 3 * layer - 3) {
y = abs(x);
step -= y;
if (x < 0) x += step;
else x -= step;
}
else {
x = -x;
y = layer - (step - (3 * layer - 3) + 1);
}
cout << x << ' ' << y << endl;
}
return 0;
}
]]>