[SDOI2009]HH的项链 和 [HEOI2012]采花两题树状数组解法对比分析

2023-10-09 15:38

本文主要是介绍[SDOI2009]HH的项链 和 [HEOI2012]采花两题树状数组解法对比分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://www.luogu.com.cn/problem/P1972

  • HH的项链这个题是静态区间查询的问题,如果用树状数组来解决,那么容易想到的方法是比如说问 [ l , r ] 的 [l,r]的 [l,r]不同贝壳数量,那么我如果用树状数组维护区间的不同贝壳数,那么答案应该是 q u e r y ( r ) − q u e r y ( l − 1 ) query(r)-query(l-1) query(r)query(l1),但是这里带来一个问题,就是 [ 1 , l ] [1,l] [1,l] [ 1 , r ] [1,r] [1,r]这两个区间里面不能有重复的贝壳,否则就会出错,那如何来解决呢?
  • 一个办法就是记录当前贝壳的上一次出现的位置,如果当前贝壳不是第一次出现,那么把它上一次出现的位置所对应的树状数组的值 − 1 -1 1,这次出现的位置所对应的树状数组的值 + 1 +1 +1,但这同样存在一个问题,如果你询问右端点在上一个出现位置前面怎么办?所以我们要先把查询时候的右端点按照从小到大的顺序排个序,然后就可以进行上述操作了,每次查询完毕就记录答案
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e6 + 100;
const int INF = 0x3f3f3f3f;
int Data[MAXN];
int a[MAXN];
int n, m;
struct st{int l, r;int id;bool operator< (st &x)const {return r < x.r;}
}s[MAXN];
int lowbit(int x){return x & -x;
}
void ADD(int x, int val){while(x <= n){Data[x] += val;x += lowbit(x);}
}
int query(int x){int res = 0;while(x > 0){res += Data[x];x -= lowbit(x);}return res;
}
int last[MAXN], pre[MAXN];
int ans[MAXN];
int main(){#ifdef LOCALfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);#endifios::sync_with_stdio(false);cin >> n;for(int i=1;i<=n;i++){cin >> a[i];pre[i] = last[a[i]];last[a[i]] = i;}cin >> m;for(int i=1;i<=m;i++){cin >> s[i].l >> s[i].r;s[i].id = i;}sort(s + 1, s + 1 + m);int now = 1;for(int i=1;i<=m;i++){while(now <= s[i].r){if(pre[now]){ADD(pre[now], -1);}ADD(now, 1);++now;}ans[s[i].id] = query(s[i].r) - query(s[i].l - 1);}for(int i=1;i<=m;i++){cout << ans[i] << '\n';}return 0;
}

https://www.luogu.com.cn/problem/P4113

  • 这个题问的也是种类数,也是静态区间查询问题,查询区间之间也是独立的,但是和上一个题的区别是必须有两个以上的同种颜色的花才能算数,这样的话我们可以再记录一个前驱的前驱,查询的时候先让前驱所对应的树状数组的值 + 1 +1 +1,前驱的前驱所对应树状数组的值 − 1 -1 1,当然前驱和前驱的前驱必须存在才能做相关操作
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e6 + 100;
const int INF = 0x3f3f3f3f;
int Data[MAXN];
int a[MAXN];
int n, c, m;
struct st{int l, r;int id;bool operator< (st &x)const {return r < x.r;}
}s[MAXN];
int lowbit(int x){return x & -x;
}
void ADD(int x, int val){while(x <= n){Data[x] += val;x += lowbit(x);}
}
int query(int x){int res = 0;while(x > 0){res += Data[x];x -= lowbit(x);}return res;
}
int last[MAXN], pre[MAXN], prepre[MAXN];
int ans[MAXN];
int main(){#ifdef LOCALfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);#endifios::sync_with_stdio(false);cin >> n >> c >> m;for(int i=1;i<=n;i++){cin >> a[i];pre[i] = last[a[i]];last[a[i]] = i;prepre[i] = pre[pre[i]];}for(int i=1;i<=m;i++){cin >> s[i].l >> s[i].r;s[i].id = i;}sort(s + 1, s + 1 + m);int now = 1;for(int i=1;i<=m;i++){while(now <= s[i].r){if(pre[now]){ADD(pre[now], 1);}if(prepre[now]){ADD(prepre[now], -1);}++now;}ans[s[i].id] = query(s[i].r) - query(s[i].l - 1);}for(int i=1;i<=m;i++){cout << ans[i] << '\n';}return 0;
}

这篇关于[SDOI2009]HH的项链 和 [HEOI2012]采花两题树状数组解法对比分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/173844

相关文章

Java程序进程起来了但是不打印日志的原因分析

《Java程序进程起来了但是不打印日志的原因分析》:本文主要介绍Java程序进程起来了但是不打印日志的原因分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java程序进程起来了但是不打印日志的原因1、日志配置问题2、日志文件权限问题3、日志文件路径问题4、程序

Java数组初始化的五种方式

《Java数组初始化的五种方式》数组是Java中最基础且常用的数据结构之一,其初始化方式多样且各具特点,本文详细讲解Java数组初始化的五种方式,分析其适用场景、优劣势对比及注意事项,帮助避免常见陷阱... 目录1. 静态初始化:简洁但固定代码示例核心特点适用场景注意事项2. 动态初始化:灵活但需手动管理代

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3