bzoj 1878 HH的项链 (树状数组+离线)

题目大意:给你一个序列,求某区间出现不同的数的个数。

貌似离线树状数组是最好的解法

先把所有询问挂在它们询问的右端点上

然后从头到尾遍历这个序列,记录这个位置的值上一次出现的位置

那么,当遍历到第i位时,如果a[i]在之前出现过,就在它上一次出现的位置-1

这个操作的意义是,第i位已经有a[i]了,那么上一次出现a[i]的位置已经失去意义

接着在这个位置+1,更新last[a[i]]。差分操作用树状数组维护

然后我们遍历以这个位置为结尾的所有询问,用树状数组查前缀和,因为在a[i]相同的位置不会重复打差分,所以query(r)-query(l-1)即为这个询问的答案。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <queue>
 5 #define inf 0x3f3f3f3f
 6 #define ll long long
 7 #define N 500100
 8 #define maxn 1000000
 9 using namespace std;
10 //re
11 int n,m,cte;
12 int a[N],head[N];
13 int lst[N*2],sum[N*2];
14 struct Ques{
15     int l,r,ans,id;
16 }ques[N];
17 struct EDGE{
18     int to,nxt;
19 }edge[N];
20 void edge_add(int u,int v)
21 {
22     cte++;
23     edge[cte].to=v;
24     edge[cte].nxt=head[u];
25     head[u]=cte;
26 }
27 int cmp1(Ques s1,Ques s2) {return s1.r<s2.r;}
28 int cmp2(Ques s1,Ques s2) {return s1.id<s2.id;}
29 void update(int x,int w) {for(int i=x;i<=maxn;i+=(i&(-i)))sum[i]+=w;}
30 int query(int x) {int ans=0;for(int i=x;i>0;i-=(i&(-i)))ans+=sum[i];return ans;}
31
32 int main()
33 {
34     //freopen("data.in","r",stdin);
35     scanf("%d",&n);
36     memset(head,-1,sizeof(head));
37     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
38     scanf("%d",&m);
39     for(int i=1;i<=m;i++)
40         scanf("%d%d",&ques[i].l,&ques[i].r),ques[i].id=i;
41     sort(ques+1,ques+m+1,cmp1);
42     for(int i=1;i<=m;i++)
43         edge_add(ques[i].r,i);
44     for(int i=1;i<=n;i++)
45     {
46         if(lst[a[i]]) update(lst[a[i]],-1);
47         update(i,1),lst[a[i]]=i;
48         for(int j=head[i];j!=-1;j=edge[j].nxt){
49             int v=edge[j].to;
50             ques[v].ans=query(ques[v].r)-query(ques[v].l-1);
51         }
52     }
53     sort(ques+1,ques+m+1,cmp2);
54     for(int i=1;i<=m;i++) printf("%d\n",ques[i].ans);
55     return 0;
56 }

原文地址:https://www.cnblogs.com/guapisolo/p/9697029.html

时间: 2024-12-13 21:50:20

bzoj 1878 HH的项链 (树状数组+离线)的相关文章

[bzoj1878] [SDOI2009]HH的项链(树状数组+离线)

1878: [SDOI2009]HH的项链 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 3210  Solved: 1619[Submit][Status][Discuss] Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此, 他的项链变得越来越长.有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同 的

BZOJ 1878 SDOI 2009 HH的项链 树状数组 + 离线处理

题目大意:有一些珠子串成的项链,珠子有不同的颜色.多次询问一段区间内有多少不同的颜色. 思路:这个题让我学会了一种巧妙的离线做法.将问题按左端点排序.处理出来每个颜色第一个出现的位置,和每个颜色下一个出现的位置.然后1到cnt循环,如果这里有一个问题的左端点是当前节点,就处理他的答案,方法是前缀合,可以用树状数组.然后把这个颜色的下一个出现的位置+1. 这样做就避免了一种颜色在询问中被处理两次. CODE: #include <cstdio> #include <cstring>

BZOJ 1878 SDOI2009 HH的项链 树状数组/莫队算法

题目大意:给定一个序列.求一个区间内有多少个不同的数 正解是树状数组 将全部区间依照左端点排序 然后每次仅仅统计左端点開始的每种颜色的第一个数即可了 用树状数组维护 我写的是莫队算法 莫队明显能搞 m√m明显慢了点可是还是能接受的一个复杂度 一開始离散化数组开小了各种秒RE-- 跪了 #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algori

BZOJ1878 SDOI2009 HH的项链 树状数组

题意:给定一个颜色序列,每组询问给出区间[l,r],求[l,r]中不同颜色的数量 题解: 首先把所有颜色离散化,然后离线,将询问按右区间升序排列.从1-N把整个序列扫一遍,设Pos[i]为第i个颜色最后出现的位置,假定当前扫到的位置为i,则更新Pos[a[i]],那么问题变成了:求一个序列(Pos)中,大于等于一个数(L)的数的数量. 用树状数组维护Pos=j的数的数量,每次查询树状数组中L-N的和即可. 貌似SDOI不喜欢考大型数据结构啊……坐等今年打脸 #include <cstdio>

\BZOJ1878 [SDOI2009]HH的项链 树状数组 或 莫队

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1878 题意概括 给出一个长度为n的序列,用m次询问,问区间Li~Ri中有多少种不同的数. 0<=数值<=1000000,n<=50000,m<=200000 题解 本题有许多做法. 这里介绍树状数组和莫队,都是离线算法. 树状数组 我们把序列按照R从小到大排序. 然后从左往右走. 依次加入数字,当前的状态,比如说搞定了前i个数字. 对于第i+1个数字,我们要给它做一个标记,但是不可

[SDOI2009]HH的项链-树状数组/线段树

树状数组: 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1000010; 4 int id[maxn],tree[maxn],vis[maxn],num[maxn]; 5 int n,m; 6 struct Tree{ 7 int l,r; 8 int pos; 9 }; 10 Tree a[maxn]; 11 int buf[17]; 12 inline void read(int &x){

luogu P1972 [SDOI2009]HH的项链 树状数组

之前只做过分块做法,补一下树状数组做法. 我们先考虑一个问题,如何求从[1,x]这一区间内元素不同的个数?显然我们只要从到到位,遇到一个新的元素,就在对应位置+1,然后使用树状数组求前缀和即可. 这里我们需要去求[x,y],所求区间的左端点也会发生变化.我们先按照[1,x]的方法预处理出这个前缀和数组.我们考虑对询问区间按照左端点排序.然后对于当前的区间[x0,y0],query(y0) - query(x0 - 1)与正确答案相比有所区别,是因为有些元素在x0左侧计算过了,而在这段区间中,对应

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

HDU 4417 - Super Mario ( 主席树 + 线段树/树状数组离线处理 + 划分树 ) 这道题有很多种做法,我先学习的是主席树.后面陆续补上线段树离线和划分树 题目大意就是给定一个区间给定一个数列,每次要求你查询区间[L,R]内不超过K的数的数量 主席树做法: 最基本的是静态第k大,这里是求静态的 <= K,差不多,在Query操作里面需要修改修改 先建立size棵主席树,然后询问的时候统计的是 第R棵主席树中[1,K]的数量 - 第L-1棵主席树中[1,K]的数量 注意这里下标

Necklace HDU - 3874 (线段树/树状数组 + 离线处理)

Necklace HDU - 3874 Mery has a beautiful necklace. The necklace is made up of N magic balls. Each ball has a beautiful value. The balls with the same beautiful value look the same, so if two or more balls have the same beautiful value, we just count