IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> E Eyjafjalla(莫队 主席树) -> 正文阅读

[数据结构与算法]E Eyjafjalla(莫队 主席树)

在这里插入图片描述在这里插入图片描述
输入

4
1 2
1 3
2 4
10 8 7 6
3
1 10 10
2 6 7
3 7 10

输出

1
0
3

数据结构题,题意就不写了

思路
首先考虑能达到的最上边,再看从最上边开始的子树有多少符合下界的,可以将用树链剖分知识(dfs序)变为一条链,再对区间操作。
考虑对温度建一棵主席树,用dfs序更新,或者对温度分块,用莫队修改。
具体不简单,详见代码
注意向上找要用倍增,温度要离散化(包括询问时的温度)

主席树

#include <bits/stdc++.h>
// #define x first
// #define y second
typedef long long ll;
const int N = 100100;
#define PII pair<int, int>
const ll mod = (ll)1e9 + 7;
using namespace std;
int n, q;
int t[N], tmp[N];                           //时间戳编号对应的权值
int h[N], e[N << 1], ne[N << 1], idx_path;  //建图
int dfn[N], low[N], timestamp;
int fa[N][31];
vector<int> ve;
struct Query {
    int num;
    int l, r;  //温度
    int x, y;
} qu[N];
struct node {
    int l, r;
    int cnt;
} tr[N * 25];
int root[N], idx;
set<int> se;
int cnt_q;
unordered_map<int, int> id;
int ans[N << 2], belong[N << 2], num;

void add_path(int u, int v) {
    idx_path++;
    e[idx_path] = v, ne[idx_path] = h[u], h[u] = idx_path;
}
void dfs1(int u, int father) {
    dfn[u] = low[u] = ++timestamp;
    ve.push_back(t[u]);
    tmp[dfn[u]] = t[u];
    fa[u][0] = father;
    for (int i = 1; i < 30; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1];

    int j;
    for (int i = h[u]; i; i = ne[i]) {
        j = e[i];
        if (j == father) continue;
        dfs1(j, u);
        low[u] = max(low[u], low[j]);
    }
}
int find_root(int x, int l, int r) {
    int zu;
    for (int i = 30; i >= 0; i--) {
        zu = fa[x][i];
        if (t[zu] >= l && t[zu] <= r)  //
            x = zu;
    }
    return x;
}

int build(int l, int r) {
    int p = ++idx;
    if (l == r) return p;
    int mid = l + r >> 1;
    tr[p].l = build(l, mid), tr[p].r = build(mid + 1, r);
    return p;
}

int insert(int p, int l, int r, int x) {
    int q = ++idx;
    tr[q] = tr[p];
    if (l == r) {
        tr[q].cnt++;
        return q;
    }
    int mid = l + r >> 1;
    if (x <= mid)
        tr[q].l = insert(tr[p].l, l, mid, x);
    else
        tr[q].r = insert(tr[p].r, mid + 1, r, x);
    tr[q].cnt = tr[tr[q].l].cnt + tr[tr[q].r].cnt;
    return q;
}

int query(int q, int p, int l, int r, int k) {  //隐含一个上界正无穷(下界k)
    if (l >= k) return tr[q].cnt - tr[p].cnt;
    int ans = 0, mid = l + r >> 1;
    if (k <= mid) ans += query(tr[q].l, tr[p].l, l, mid, k);
    ans += query(tr[q].r, tr[p].r, mid + 1, r, k);
    return ans;
}
void solve() {
    int tot = 0;
    int u, v;
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        scanf("%d%d", &u, &v);
        add_path(u, v), add_path(v, u);
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", &t[i]);
        se.insert(t[i]);
    }
    dfs1(1, 0);
    // for (int i = 0; i < ve.size(); i++) {
    //     cout << ve[i] << "*";
    // }
    // cout << "\n";
    scanf("%d", &q);
    int x, l, r;
    for (int i = 1; i <= q; i++) {
        scanf("%d%d%d", &x, &l, &r);
        if (!(t[x] >= l && t[x] <= r)) {
            ans[i] = 0;
            continue;
        }
        se.insert(l);
        se.insert(r);
        int root = find_root(x, l, r);
        qu[cnt_q++] = {i, l, r, dfn[root], low[root]};
    }
    for (auto it : se) id[it] = ++tot;
    int ql, qr;
    root[0] = build(1, tot);
    for (int i = 1; i - 1 < ve.size(); i++) {
        root[i] = insert(root[i - 1], 0, tot, id[ve[i - 1]]);
    }
    for (int i = 0; i < cnt_q; i++) {
        int l, r, k;
        l = qu[i].x, r = qu[i].y;
        k = id[qu[i].l];
        ans[qu[i].num] = query(root[r], root[l - 1], 0, tot, k);
    }
    for (int i = 1; i <= q; i++) {
        cout << ans[i] << "\n";
    }
}
int main() {
    int t = 1;
    // cin >> t;
    while (t--) solve();
    return 0;
}

莫队

在这里插入代码片#include <bits/stdc++.h>
// #define x first
// #define y second
typedef long long ll;
const int N = 100100;
#define PII pair<int, int>
const ll mod = (ll)1e9 + 7;
using namespace std;
int n, q;
int t[N], tmp[N];                      //时间戳编号对应的权值
int h[N], e[N << 1], ne[N << 1], idx;  //建图
int dfn[N], low[N], timestamp;
int fa[N][31];

struct Query {
    int num;
    int l, r;  //温度
    int x, y;
} qu[N];
int cnt_q;
set<int> se;
unordered_map<int, int> id;
int cnt[N << 2];
int sum[N << 2], val[N << 2], num;
int ans[N << 2], belong[N << 2];
int len, block, curl = 1, curr;

void add_path(int u, int v) {
    idx++;
    e[idx] = v, ne[idx] = h[u], h[u] = idx;
}
void dfs(int u, int father) {
    dfn[u] = low[u] = ++timestamp;
    tmp[dfn[u]] = t[u];
    fa[u][0] = father;
    for (int i = 1; i < 30; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1];

    int j;
    for (int i = h[u]; i; i = ne[i]) {
        j = e[i];
        if (j == father) continue;
        dfs(j, u);
        low[u] = max(low[u], low[j]);
    }
}
int find_root(int x, int l, int r) {
    int zu;
    for (int i = 30; i >= 0; i--) {
        zu = fa[x][i];
        if (t[zu] >= l && t[zu] <= r)  //
            x = zu;
    }
    return x;
}
bool cmp(Query u, Query v) {
    if (u.x / len == v.x / len) return u.y < v.y;
    return u.x < v.x;
}
void build() {
    int maxx = se.size();
    block = sqrt(maxx);  //注意
    num = maxx / block;
    if (maxx % block) num++;
    for (int i = 1; i <= maxx; i++) {  //注意
        belong[i] = (i - 1) / block + 1;
        sum[belong[i]] += val[i];
    }
}
void add(int x) {
    int fx = id[tmp[x]];
    val[fx]++;
    sum[belong[fx]]++;
}
void del(int x) {
    int fx = id[tmp[x]];
    val[fx]--;
    sum[belong[fx]]--;
}
int ask(int ql, int qr) {
    int ret = 0;
    int st = belong[ql], ed = belong[qr];
    if (st == ed) {
        for (int i = ql; i <= qr; i++)  //
            ret += val[i];

        return ret;
    }
    for (int i = ql; belong[i] == belong[ql]; i++) ret += val[i];

    for (int i = qr; belong[i] == belong[qr]; i--) ret += val[i];

    for (int i = st + 1; i < ed; i++) ret += sum[i];

    return ret;
}
void solve() {
    int tot = 0;
    int u, v;
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        scanf("%d%d", &u, &v);
        add_path(u, v), add_path(v, u);
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", &t[i]);
        se.insert(t[i]);
    }
    dfs(1, 0);
    len = sqrt(n);
    scanf("%d", &q);
    int x, l, r;
    for (int i = 1; i <= q; i++) {
        scanf("%d%d%d", &x, &l, &r);
        if (!(t[x] >= l && t[x] <= r)) {//答案等于0的不用保存
            ans[i] = 0;
            continue;
        }
        se.insert(l);
        se.insert(r);
        int root = find_root(x, l, r);
        qu[cnt_q++] = {i, l, r, dfn[root], low[root]};
    }
    for (auto it : se) id[it] = ++tot;
    build();
    sort(qu, qu + cnt_q, cmp);
    int ql, qr;
    curl = 1, curr = 0;
    for (int i = 0; i <= cnt_q; i++) {
        int ql = qu[i].x, qr = qu[i].y;
        while (curl > ql) add(--curl);

        while (curl < ql) del(curl++);

        while (curr < qr) add(++curr);

        while (curr > qr) del(curr--);

        ql = id[qu[i].l];
        qr = id[qu[i].r];
        ans[qu[i].num] = ask(ql, qr);
        // cout << "*" << ans[qu[i].num] << "\n";
    }

    for (int i = 1; i <= q; i++) {
        cout << ans[i] << "\n";
    }
}
int main() {
    int t = 1;
    // cin >> t;
    while (t--) solve();
    return 0;
}

莫队最快用时600ms+
主席最快树用时400ms+

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:43:11  更:2021-08-21 15:45:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:51:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码