『学习笔记』树套树(todo)

维护一个序列:

  1. 单点修改。
  2. 给定 \(x\),查询区间有多少个位置 \(i\) 满足 \(a_i=x\)

线段树套 map,可以 \(O(\log)\)。哈希表?\(O(1)\)

树状数组套 map

map<int,int> t[N];
int find(int x,int y){
    // 查询 [1,x] 中 y 出现次数
    int ans=0;
    for(int i=x; i; i-=lowbit(i))
        ans+=t[i][y];
    return ans;
}
void insert(int x,int y){
    // 在 x 位置插入 y
    for(int i=x; i<=n; i+=lowbit(i))
        t[i][x]--,t[i][y]++;
}

如果把询问改为 \(a_i<x\)

平衡树 t[N];
// 或者 线段树 t[N];
int find(int x,int y){
    // 查询 [1,x] 中 <y 个数
    int ans=0;
    for(int i=x; i; i-=lowbit(i))
        ans+=t[i].find(y);
    return ans;
}
void insert(int x,int y){
    // 在 x 位置插入 y
    for(int i=x; i<=n; i+=lowbit(i))
        t.insert(y);
}

树状数组套平衡树/线段树/...,即树套树。

可以解决动态二维数点。

树套树难点在于维护内层数据结构。

P4396 [AHOI2013] 作业

三维数点。树套树 / cdq 分治。

P3157 [CQOI2011] 动态逆序对

考虑每删一个点的影响,转化为区间查询和单点删除。

P4690 [Ynoi2016] 镜子里的昆虫 (弱化版)

  1. 单点修改。
  2. 询问区间出现了多少种不同的数。

维护 \(pre_i\) 表示 \(i\) 之前第一个与 \(i\) 相同的数,询问即 \(pre_i<l(i \in[l,r])\) 个数。

对于修改,只会影响 \(O(1)\) 个元素。考虑用 set 维护每钟值存在的下标,二分找一下修改即可。

P4690 [Ynoi2016] 镜子里的昆虫

  1. 区间修改。
  2. 询问区间出现了多少种不同的数。

同样维护 \(pre_i\),颜色段均摊。对于修改覆盖的每一个颜色段,仅左端点的 \(pre_i\) 会改变。

树状数组维护,\(O(\log)\)

P3242 [HNOI2015] 接水果

考虑每个盘子 \((x,y,k)\) 的贡献,只有 \(x\)\(y\) 子树内的两个点连成的路径合法,那么拍成 dfn,可以转化为矩阵 \(+k\)。询问即可转化为单点覆盖矩形 kth。树状数组上差分,转化为单点修改区间查询。套一个值域线段树求 kth,方便二分。

posted @ 2025-01-05 22:57  仙山有茗  阅读(20)  评论(0)    收藏  举报