Loading

解题报告(不是 杂项复习 & 日记 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\)

P3793

什么 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;
}

P5854

#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\),但是开局被卡。

posted @ 2024-11-25 11:59  Merlin_Meow  阅读(35)  评论(0)    收藏  举报
Sakana Widget 自定义角色自适应示例