数据结构入门级题目瞎做

\(1.\) [省选联考 2021 A/B 卷] 宝石
观察到题目中收集的顺序都已经给定,所以对于每一个宝石,收集完它之后的下一个宝石的位置是知道的。于是,我们可以倍增预处理出每个位置的宝石被收集后第 \(2^x\) 个该收集的宝石的位置。把路径拆成 \(s - lca\)\(lca - t\)\(s - lca\) 部分可以直接倍增。但是 \(lca - t\) 该怎么办呢?逆着题目中给的宝石顺序再倍增预处理一下,然后从终点跳。由于我们不知道最终的位置是啥,并且这个位置具有单调性,所以我们可以二分这个终点 \(mid\)。然后的问题就是起点和终点不一定有第一个和第 \(mid\) 个宝石。于是我们考虑把询问离线下来, \(dfs\) 一遍,对于每一种宝石开一个 \(vector\) 即可。

代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <cstdlib>
#include <cmath>
using namespace std;
#define pii pair<int,int>
#define mp make_pair
const int N = 2e5 + 10, M = 5e4 + 10;
int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
int n, m, c, tot, u, v, t, q;
int p[M], a[N], head[N], ver[N * 2], last[N * 2], f[N][30], L[N], lt[N][30], nt[N][30];
int nf[N], dep[N], b[M], d[M], back[M], ans[N];
vector<int> ct[M];
vector<pii> qq[N];
void add(int x, int y)
{
    ver[++tot] = y;
    last[tot] = head[x];
    head[x] = tot;
}
void dfs(int x, int fa)
{
    ct[a[x]].push_back(x);
    dep[x] = dep[fa] + 1;
    if (!ct[p[1]].empty()) nf[x] = ct[p[1]].back();
    for (int i = head[x]; i; i = last[i])
    {
        int y = ver[i];
        if (y == fa) continue;
        f[y][0] = x;
        for (int j = 1; j <= t; j++) f[y][j] = f[f[y][j - 1]][j - 1];
        if (!ct[b[a[y]]].empty()) nt[y][0] = ct[b[a[y]]].back();
        if (!ct[d[a[y]]].empty()) lt[y][0] = ct[d[a[y]]].back();
        for (int j = 1; j <= t; j++) nt[y][j] = nt[nt[y][j - 1]][j - 1];
        for (int j = 1; j <= t; j++) lt[y][j] = lt[lt[y][j - 1]][j - 1];
        dfs(y, x);
    }
    ct[a[x]].pop_back();
}
int lca(int x, int y)
{
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = t; i >= 0; i--) {if (dep[f[x][i]] >= dep[y]) x = f[x][i];}
    if (x == y) return x;
    for (int i = t; i >= 0; i--)
    {
        if (f[x][i] != f[y][i])
        {
            x = f[x][i];
            y = f[y][i];
        }
    }
    return f[x][0];
}
int find(int x, int y, int flag)
{
    if (!x) return -1;
    if (dep[x] < dep[y]) return -1;
    if (flag) {for (int i = t; i >= 0; i--) {if (dep[nt[x][i]] >= dep[y]) x = nt[x][i];} return x;}
    for (int i = t; i >= 0; i--) {if (dep[lt[x][i]] >= dep[y]) x = lt[x][i];} return x;
}
void dfs2(int x, int fa)
{
    ct[a[x]].push_back(x);
    int len = qq[x].size();
    for (int i = 0; i < len; i++)
    {
        int s = qq[x][i].first, LCA = lca(x, s);
        int pos = find(nf[s], LCA, 1);
        int l = back[a[pos]] + 1, r = c, mid;
        ans[qq[x][i].second] = back[a[pos]];
        while (l <= r)
        {
            mid = (l + r) >> 1;
            if (!ct[p[mid]].empty())
            {
                int pp = find(ct[p[mid]].back(), LCA, 0);
                if (pp == -1) r = mid - 1;
                else
                {
                    if (back[a[pp]] <= back[a[pos]] + 1) l = mid + 1, ans[qq[x][i].second] = mid;
                    else r = mid - 1;
                }
            }
            else r = mid - 1; 
        }
    }
    for (int i = head[x]; i; i = last[i])
    {
        int y = ver[i];
        if (y == fa) continue;
        dfs2(y, x);
    }
    ct[a[x]].pop_back();
}
int main()
{
    for (int i = 2; i <= 2e5; i++) L[i] = L[i >> 1] + 1;
    n = read(), m = read(), c = read(); t = L[n];
    for (int i = 1; i <= c; i++) p[i] = read(), b[p[i - 1]] = p[i], d[p[i]] = p[i - 1], back[p[i]] = i;
    for (int i = 1; i <= n; i++) a[i] = read();
    for (int i = 1; i < n; i++)
    {
        u = read(), v = read();
        add(u, v); add(v, u);
    }
    q = read();
    for (int i = 1; i <= q; i++)
    {
        u = read(), v = read();
        qq[v].push_back(mp(u, i));
    }
    dfs(1, 0);
    dfs2(1, 0);
    for (int i = 1; i <= q; i++) printf("%d\n", ans[i]);
    return 0;
}

\(2.\) 序列 题解

\(3.\) [AHOI2013] 作业 代码

\(4.\) [SNOI2017] 一个简单的询问 代码

\(5.\) [Ynoi2016] 这是我自己的发明 代码

\(6.\) [ZJOI2013] K大数查询 代码

\(7.\) [国家集训队] 矩阵乘法

\(8.\) [模板] 二逼平衡树

\(9.\) [NOI2010] 超级钢琴

\(10.\) [HEOI2016/TJOI2016]排序

\(11.\) CF444C DZY Loves Colors

\(12.\) CF1638C Colorful Operations

posted @ 2022-01-02 21:10  David24  阅读(105)  评论(2编辑  收藏  举报