当前位置: 首页 > news >正文

Fenwick 树进行快速统计

Fenwick 树(二叉索引树)是一种高效的数据结构,主要用于解决前缀和查询单点更新问题,时间复杂度均为O(log n),适用于需要频繁更新元素并查询前缀和的场景(如本题统计满足条件的对数)。

核心功能

Fenwick 树支持两种基本操作:

  1. 单点更新:给数组中某个位置的元素加上一个值。
  2. 前缀和查询:计算数组中前k个元素的总和。

原理与结构

Fenwick 树的核心是利用二进制的特性(低位的1)来划分区间,实现高效的更新和查询。

结构特点:
  • 树是1-based 索引(从 1 开始计数,方便二进制操作)。
  • 每个节点i负责管理一段区间,区间范围由i的二进制中最低位的 1决定(例如i=6的二进制是110,最低位的 1 对应的值是2,所以节点 6 管理[6-2+1, 6] = [5,6])。

基本操作详解

1. 单点更新(update(i, delta)

给位置i的元素增加delta步骤:从i开始,不断加上i的二进制中最低位的 1(即i += i & -i),直到超过树的大小。作用:更新所有包含位置i的区间节点。

void update(int idx, int delta) {for (; idx <= size; idx += idx & -idx) {tree[idx] += delta;}
}
2. 前缀和查询(query(i)

计算前i个元素的总和。步骤:从i开始,不断减去i的二进制中最低位的 1(即i -= i & -i),直到i=0,累加经过的节点值。作用:将前i个元素拆分成若干个被节点管理的区间,求和后得到前缀和。

int query(int idx) {int res = 0;for (; idx > 0; idx -= idx & -idx) {res += tree[idx];}return res;
}

在本题中的应用

在一个序列2n,1-n每个数都会出现两次,计算有多少对数的数,满足x1 < y1 < x2 < y2。

本题需要统计满足x1 < y1 < x2 < y2的数对数量:

  1. 先将非相邻数按x1排序(确保处理顺序满足x1' < x1)。
  2. 对每个数的x2进行坐标压缩(将分散的x2值映射到连续的小范围,节省空间)。
  3. 用 Fenwick 树记录已处理数的x2,对于当前数的x2,通过query(x2-1)快速统计出之前所有x2' < 当前x2的数量(即满足x1' < x1 < x2' < x2的对数)。

#include <bits/stdc++.h>
using namespace std;

// Fenwick树( Binary Indexed Tree )用于高效统计
struct Fenwick {
int size;
vector<int> tree;

    // 初始化大小为n的Fenwick树
Fenwick(int n) : size(n), tree(n + 2, 0) {}  // 1-based索引

    // 更新操作:在idx位置加delta
void update(int idx, int delta) {
for (; idx <= size; idx += idx & -idx) {
tree[idx] += delta;
}
}

    // 查询操作:求[1, idx]的前缀和
int query(int idx) {
int res = 0;
for (; idx > 0; idx -= idx & -idx) {
res += tree[idx];
}
return res;
}
};

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);

    int T;
cin >> T;
while (T--) {
int N;
cin >> N;
int len = 2 * N;
vector<int> A(len);
for (int i = 0; i < len; ++i) {
cin >> A[i];
}

        // 记录每对夫妇的两个位置
vector<pair<int, int>> pos(N + 1);  // pos[x] = (第一个出现位置, 第二个出现位置)
vector<int> first_occurrence(N + 1, -1);
for (int i = 0; i < len; ++i) {
int x = A[i];
if (first_occurrence[x] == -1) {
first_occurrence[x] = i;  // 记录第一次出现位置
} else {
pos[x] = {first_occurrence[x], i};  // 记录第二次出现位置
}
}

        // 筛选出原本不相邻的数
vector<pair<int, int>> S;
for (int x = 1; x <= N; ++x) {
auto [x1, x2] = pos[x];
if (x2 - x1 != 1) {  // 相邻的条件是位置差为1
S.emplace_back(x1, x2);
}
}

        // 按第一个位置x1排序(确保我们按顺序处理)
sort(S.begin(), S.end());

        // 坐标压缩:将x2值映射到较小的范围,便于Fenwick树处理
vector<int> x2s;
for (auto [x1, x2] : S) {
x2s.push_back(x2);
}
sort(x2s.begin(), x2s.end());
x2s.erase(unique(x2s.begin(), x2s.end()), x2s.end());  // 去重
int m = x2s.size();

        // 用Fenwick树统计符合条件的对数
Fenwick fenwick(m);
long long ans = 0;

        for (auto [x1, x2] : S) {
// 找到x2在压缩后的排名(1-based)
int r = lower_bound(x2s.begin(), x2s.end(), x2) - x2s.begin() + 1;

// 查询当前有多少个x2' < x2(即满足交叉条件的数量)
ans += fenwick.query(r - 1);

// 将当前x2加入Fenwick树
fenwick.update(r, 1);
}

        cout << ans << '\n';
}

    return 0;
}

http://www.dtcms.com/a/515694.html

相关文章:

  • Cocos creator2.4.4 处理 16KB 问题
  • 旅游网站的设计的前提成都那家网站做的好
  • undefined reference to `cv::String::dea llocate()‘
  • 计划任务原理及实战
  • 做网站设计最好的公司做旅游网站的论文
  • 【Android】Handler/Looper机制相关的类图和流程图
  • ARM《1》_回顾gcc、动态编译和静态编译、MakeFile的使用
  • 网络环路:隐形威胁的破解之道
  • stm32 can错误中断不处理
  • 我们平常说的连网是指什么?
  • 网站优化人员新乡市延津县建设局网站
  • 网站建设分析从哪几个方面东莞市招聘网
  • 设计模式-责任链模式:从鞋厂审批流程看请求处理的艺术
  • 21_AI智能体开发架构搭建之基于Flask蓝图模块化构建可扩展的知识库服务实践
  • 【手机篇】AI深度学习在手机摄像头模组支架外观检测应用方案
  • 手机版矩阵系统源码搭建与定制开发:深度技术解析与落地实践
  • 做网站首页可以用传媒公司吗软件 项目管理系统
  • 舟山建设工程信息网站北京设计公司招聘
  • Elasticsearch还有哪些常用的分词器?
  • 使用CNN构建VAE
  • TESOLLO:使用MANUS Franka机械臂提高机器人灵活性
  • 西宁建设网站软件陕西交通建设有限公司网站
  • COMAU柯马焊接机器人气保焊省气
  • 西门子 1500 PLC 依托 Ethernet/ip 转 Modbus RTU联合发那科机器人优化生产流程
  • 全球首个超声多模态大模型!百度百舸支撑海豚智能实现高效训练与稳定服务
  • 统一机器人描述格式---URDF
  • SCARA 机器人点到点(PTP)轨迹规划方法
  • 岳阳市网站建设推广搜索引擎优化是什么?
  • 阿里云代理商:阿里云负载均衡是什么?
  • 安川机器人motoplus二次开发实现socket 变量读写 SKILLSND命令接收 轨迹实时修正功能