数据结构(树状数组):HEOI2012 采花

【题目描述】

萧薰儿是古国的公主,平时的一大爱好是采花。

今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花。花园足够大,容纳了n朵花,花有c种颜色(用整数1-c表示),且花是排成一排的,以便于公主采花。公主每次采花后会统计采到的花的颜色数,颜色数越多她会越高兴!同时,她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵。为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花。由于时间关系,公主只能走过花园连续的一段进行采花,便让女仆福涵洁安排行程。福涵洁综合各种因素拟定了m个行程,然后一一向你询问公主能采到多少朵花(她知道你是编程高手,定能快速给出答案!),最后会选择令公主最高兴的行程(为了拿到更多奖金!)。

【输入格式】

第一行四个空格隔开的整数n、c以及m。接下来一行n个空格隔开的整数,每个数在[1, c]间,第i个数表示第i朵花的颜色。接下来m行每行两个空格隔开的整数l和r(l ≤ r),表示女仆安排的行程为公主经过第l到第r朵花进行采花。

【输出格式】

共m行,每行一个整数,第i个数表示公主在女仆的第i个行程中能采到的花的颜色数。

【样例输入】

5  3 5
  1  2 2 3 1
  1  5
  1  2
  2  2
  2  3
  3  5
  

【样例输出】

2
  0 0 1 0
  【样例说明】
  询问[1, 5]:公主采颜色为1和2的花,由于颜色3的花只有一朵,公主不采;询问[1, 2]:颜色1和颜色2的花均只有一朵,公主不采;
  询问[2, 2]:颜色2的花只有一朵,公主不采;
  询问[2, 3]:由于颜色2的花有两朵,公主采颜色2的花;
  询问[3, 5]:颜色1、2、3的花各一朵,公主不采。
  

【提示】

【数据范围】

对于100%的数据,1 ≤ n ≤    10^6,c ≤ n,m ≤10^6。

  找到每个位置的值上一次出现的位置,将询问离线并按右端点排序,然后用bit维护答案,使得直接查找可以获得答案,题目还是很巧妙的。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdio>
 5 using namespace std;
 6 const int N=1000010;
 7 int n,c,Q;
 8 int a[N],p[N],h[N],pre[N],bit[N],Ql[N],Qr[N],ans[N];
 9 void Add(int x,int d){
10     while(x<N){
11         bit[x]+=d;
12         x+=x&(-x);
13     }
14 }
15 int Query(int x){
16     int ret=0;
17     while(x){
18         ret+=bit[x];
19         x-=x&(-x);
20     }
21     return ret;
22 }
23 bool cmp(int x,int y){return Qr[x]<Qr[y];}
24 int main(){
25     freopen("1flower.in","r",stdin);
26     freopen("1flower.out","w",stdout);
27     scanf("%d%d%d",&n,&c,&Q);
28     for(int i=1;i<=n;i++){
29         scanf("%d",&a[i]);
30         pre[i]=h[a[i]];
31         h[a[i]]=i;
32     }
33     for(int i=1;i<=Q;p[i]=i,i++)
34         scanf("%d%d",&Ql[i],&Qr[i]);
35     sort(p+1,p+Q+1,cmp);
36     for(int i=1,t=1;i<=Q;i++){
37         if(pre[i]){
38             Add(pre[i]+1,-1);
39             Add(pre[pre[i]]+1,1);
40         }
41         while(Qr[p[t]]==i){
42             ans[p[t]]=Query(Ql[p[t]]);
43             t+=1;
44         }
45     }
46     for(int i=1;i<=Q;i++)
47         printf("%d\n",ans[i]);
48     return 0;
49 }
时间: 2024-10-11 21:34:53

数据结构(树状数组):HEOI2012 采花的相关文章

数据结构——树状数组

我们今天来讲一个应用比较广泛的数据结构——树状数组 它可以在O(nlogn)的复杂度下进行单点修改区间查询,下面我会分成三个模块对树状数组进行详细的解说,分别是树状数组基本操作.树状数组区间修改单点查询的实现.树状数组查询最值的实现 一. 树状数组一般分为三种操作,初始化.修改.查询 在讲基本操作之前,我们先来看一张图 这张图就是树状数组的存储方式,对于没有接触过树状数组的人来说看懂上面这张图可能有些困难,上图的A数组就是我们的原数组,C数组则是我们需要维护的数组,这样存储能干什么呢,比如我们在

HDU 1556 数据结构-树状数组-改段求点

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1556 解题思路:树状数组,只要了解树状数组的原理就不用死记模板了,总之树状数组管理的就是前缀和,高度越高的的结点管理的范围越广 所以要是改点求段:更改一个点就要向上传递 所以要是改段求点:更改一个点就要向下传递 代码: #include <cstdio> #include <iostream> #include <cstring> using namespace std;

数据结构——树状数组篇

原地址:My CSDN Blog  那边还未通过审核,先看这边的吧…… 线段树是一个很好的维护区间关系的这样的一个数据结构,但是,很多时候我们可以用更小空间.更快速度(更大尺寸呢.,全景天窗,五菱宏光?)的数据结构来维护一个前缀关系. ??? 上面的这张图是表示的一个有8个叶子节点的线段树,接下去,我们给它进行一个变形: ??? 然后呢,我们把2.4.6.8.……这样的元素推到最顶端的空上边去,想让2表示1-2这段区间,让4表示1-4这段区间,让6表示5-6这段区间,让8表示1-8这段区间. 然

实用数据结构---树状数组(二叉索引树)

树状数组适用于动态连续和查询问题,就是给定一个区间, 查询某一段的和或者修改某一位置的值. 关于树状数组的结构请去百度百科,否则将看不懂下面内容 我们看这个题 士兵杀敌(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧. 南将军的某次询问之后士兵i可能又杀敌q人,之后南将军再询问的时候,需要考虑到新

用树状数组处理逆序对[数据结构][树状数组]

逆序对 ——!x^n+y^n=z^n 可以到这里[luogu]: https://www.luogu.org/problem/show?pid=1908 题意:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对.知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目. 假如为这些数为: 8 2 3 1 7 如果我们把数一个个加进来,用一个数组a[i]统计i出现了几次. a的初始状态: 8加进来后: 由于不存在比8大的数,说明没有产生逆序对 2加进来后: 统计比2大

ACM数据结构-树状数组

模板: int n; int tree[LEN]; int lowbit(int x){ return x&-x; } void update(int i,int d){//index,delta while(i<=n){ tree[i]+=d; i+=lowbit(i); } } int getsum(int i){ int ans=0; while(i>0){ ans+=tree[i]; i-=lowbit(i); } return ans; } 示意图: 1.Ultra-Quic

[数据结构] 树状数组 的C程序实现

int tree[100001];//树状数组,用于取区间[x,y]的数据的和 /* & 特殊运算,t&(-t)的值(十进制),就是t在2进制下,从右往左数第一个1出现的位置. 结合树状数组的特殊性质,这个值有用 */ int lowbit(int t) { return t&(-t); } /* 假设对处在数组序号x的数据进行了更改,让x位置的数据有了增量v 对树状数组进行如下修改,使相关的包含x位数据的和都增加v 根据树状数组的性质,也就是对下标为 x, x+lowbit(x)

2019.9.25 初级数据结构——树状数组

一.树状数组基础 学OI的同学都知道,位运算(对二进制的运算)比普通运算快很多.同时我们接触到了状态压缩的思想(即将0-1的很多个状态压缩成十进制的一个数,每一个二进制位表示一个状态).由于在实际做题过程当中,由于数据范围限制,我们必须采用更高效的存储.查询方法,于是树状数组应运而生. 首先我们检查传统的存储状态.对于数组的每一个下标i,其所存储的有效信息只有一个a[i](这是传统数组).而对于树状数组,我们每一位下标可以存储lowbit(i)个有效信息.这个lowbit运算一会再说.所以尽管树

C++-hdu1166-敌兵布阵[数据结构][树状数组]

单点修改+区间查询=树状数组 空间复杂度O(n) 时间复杂度O(mlogn) 1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <queue> 5 #include <vector> 6 #include <cstdio> 7 #include <cstdlib> 8 #include <cstring> 9 #include <

C++-hdu1394-Minimum Inversion Number[数据结构][树状数组]

给出0~n-1的一个排列,可以整体移动,求逆序对最小值 把数字num[i]的加入,等价于树状数组的第n-num[i]位加1 因为num[i]是第 (n-1)-num[i]+1=n-num[i]大的数字,产生逆序对,只可能在其之前已经插入了数字,此时直接区间查询即可 1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <queue> 5 #include <vector>