解题报告(不是 杂项复习 & 日记 2024/11/25
今天是胡乱复习时间。
ST 表
令 \(f_{i,j}\) 表示区间 \([i,i+2^j-1]\) 的最大值。
显然 \(f_{i,0}=a_i\)。
那么 \(f_{i,j}=\max(f_{i,j-1},f_{i+2^{j-1},j-1})\)
对于每个询问 \([l,r]\),分成 \([l,l+2^k-1]\) 与 \([r-2^k+1,r]\) 处理,最大值即为答案。其中 \(k=\lfloor \log_2(r-l+1)\rfloor\)。
void init()
{
logn[1] = 0, logn[2] = 1;
for (int i = 3; i < maxN; i++)
logn[i] = logn[i / 2] + 1;
for (int i = 1; i <= n; i++)
f[i][0] = a[i];
int k = logn[n];
for (int j = 1; j <= k; j++)
for (int i = 1; i <= n - (1 << j) + 1; i++)
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
int query(int l, int r)
{
int k = logn[r - l + 1]; // log(r - l + 1) / log(2);
return max(f[l][k], f[r - (1 << k) + 1][k]);
}
这个实现的复杂度疑似不严格?
pb_ds Hash 表
开散列法是废物
以 P2580 为例。
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
__gnu_pbds::gp_hash_table<string, int> M;
int n, m;
string s;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
while (n--)
{
cin >> s;
M[s] = 1;
}
cin >> m;
while (m--)
{
cin >> s;
if (M[s] == 1)
{
cout << "OK" << endl;
M[s] = 2;
}
else if (M[s] == 2)
cout << "REPEAT" << endl;
else
cout << "WRONG" << endl;
}
return 0;
}
没有对 pair 的支持但似乎无伤大雅。
插播一条劲爆消息
9:05 a.m. HZOJ 两个站点全部爆炸。
Edge 认为 “HZOJ 发回了不正常和不正确的凭据”。
然而 Chrome 说我的时钟快了。
9:20 a.m. 修好了。
双端栈
这什么啊我怎么没听过
啊什么就是
deque?哦确实那没事了
Kruskal
只是看到一个好玩的 例题 于是来做一下
题目等价于连一个 \(k\) 棵树组成的森林,使边权和最小。
显然当且仅当 \(n\lt k\) 时存在无解情况。
否则按照 Kruskal 的思想连 \(n-k\) 条边即可。
你说得对但是今天下雨没有棉花糖一样的云 QAQ
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 10;
const int maxm = 10000 + 10;
int n, m, k;
int fa[maxn];
struct edge
{
int u, v, w;
} e[maxm];
bool cmp(edge a, edge b) { return a.w < b.w; }
void init()
{
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
fa[i] = i;
for (int i = 1; i <= m; i++)
cin >> e[i].u >> e[i].v >> e[i].w;
sort(e + 1, e + m + 1, cmp);
}
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
init();
if (n < k)
cout << "No Answer" << endl;
int cnt = 0, ans = 0;
for (int i = 1; i <= m; i++)
{
int u = e[i].u, v = e[i].v, w = e[i].w;
int fu = find(u), fv = find(v);
if (fu != fv)
{
fa[fv] = fu;
cnt++;
ans += w;
}
if (cnt == n - k)
break;
}
cout << ans << endl;
return 0;
}
笛卡尔树
建树:
// stk 维护笛卡尔树中节点对应到序列中的下标
for (int i = 1; i <= n; i++) {
int k = top; // top 表示操作前的栈顶,k 表示当前栈顶
while (k > 0 && w[stk[k]] > w[i]) k--; // 维护右链上的节点
if (k) rs[stk[k]] = i; // 栈顶元素.右儿子 := 当前元素
if (k < top) ls[i] = stk[k + 1]; // 当前元素.左儿子 := 上一个被弹出的元素
stk[++k] = i; // 当前元素入栈
top = k;
}
//By OI-Wiki
值得注意的是根节点是 \(stk_1\)。
什么 STA_Morlin 快乐题。
#include <bits/stdc++.h>
using namespace std;
namespace GenHelper
{
unsigned z1, z2, z3, z4, b;
unsigned rand_()
{
b = ((z1 << 6) ^ z1) >> 13;
z1 = ((z1 & 4294967294U) << 18) ^ b;
b = ((z2 << 2) ^ z2) >> 27;
z2 = ((z2 & 4294967288U) << 2) ^ b;
b = ((z3 << 13) ^ z3) >> 21;
z3 = ((z3 & 4294967280U) << 7) ^ b;
b = ((z4 << 3) ^ z4) >> 12;
z4 = ((z4 & 4294967168U) << 13) ^ b;
return (z1 ^ z2 ^ z3 ^ z4);
}
}
void srand(unsigned x)
{
using namespace GenHelper;
z1 = x;
z2 = (~x) ^ 0x233333333U;
z3 = x ^ 0x1234598766U;
z4 = (~x) + 51;
}
int read()
{
using namespace GenHelper;
int a = rand_() & 32767;
int b = rand_() & 32767;
return a * 32768 + b;
}
#define int unsigned long long
const int maxn = 20000000 + 10;
int n, m, s;
int w[maxn];
int ls[maxn], rs[maxn];
int stk[maxn];
int init()
{
int top = 0;
for (int i = 1; i <= n; i++)
{
int k = top;
while (k > 0 && w[stk[k]] < w[i])
k--;
if (k)
rs[stk[k]] = i;
if (k < top)
ls[i] = stk[k + 1];
stk[++k] = i;
top = k;
}
return stk[1];
}
int query(int rt, int l, int r)
{
while (rt < l || rt > r)
rt = rt < l ? rs[rt] : ls[rt];
return rt;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m >> s;
srand(s);
for (int i = 1; i <= n; i++)
w[i] = read();
int root = init(), ans = 0;
while (m--)
{
int l = read() % n + 1, r = read() % n + 1;
if (l > r)
swap(l, r);
ans += w[query(root, l, r)];
}
cout << ans << "\n";
return 0;
}
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 10000000 + 10;
int n;
int w[maxn];
int ls[maxn], rs[maxn];
int stk[100];
int ansl, ansr;
int init()
{
int top = 0;
for (int i = 1; i <= n; i++)
{
int k = top;
while (k > 0 && w[stk[k]] > w[i])
k--;
if (k)
rs[stk[k]] = i;
if (k < top)
ls[i] = stk[k + 1];
stk[++k] = i;
top = k;
}
return stk[1];
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> w[i];
init();
for (int i = 1; i <= n; i++)
{
ansl ^= i * (ls[i] + 1);
ansr ^= i * (rs[i] + 1);
}
cout << ansl << ' ' << ansr << endl;
return 0;
}
看了一下笛卡尔树突然就 11:50 a.m. 了呢。雨似乎也停了。
刚才准备学笛卡尔树的时候死机了,VS Code 自动保存救我一命。
和 gzxworld 辩论了 LCA 的求法。
反正我的结论是不如暴力自顶向下找。
下午。
吃饭的时候被 D,说笛卡尔树不如二毛子 & 四毛子。
但是我不会。遂放弃。
滚回去补 DP 和 字符串。但是啥也没做出来,遂不记。
2:54 p.m. HZOJ RMJ CF 的 bot 复活了,喜提两发爆蛋。
救活了 CF1200E,死因是用来分隔的串太规整了。
试图用字符串哈希救 CF126B,结果被硬控 1h。
这就是唐。
另外找到了新的模数 \(41620081219\),但是开局被卡。

浙公网安备 33010602011771号