[ SDOI 2009 ] HH的项链 & [ HEOI 2012 ] 采花
\(\\\)
\(Description\)
给出一个长为\(N\)的序列,\(M\)次询问区间\([L_i,R_i]\)内不同数字的个数。
- \(N\in [1,5\times 10^4]\),\(M\in [1,2\times 10^5]\),\(L_i,R_i\in [1,N]\)
\(\\\)
\(Solution\)
- 离线做法,将询问按右端点从小到大排序。
- 对下标开树状数组,每次添加数字在该位置\(+1\),在上一次该数字出现的位置\(-1\),然后将能回答询问以前缀和相减的方式都回答了。
- 关于正确性,如上做法可以看成只为每个颜色保留最后一次出现的标记,因为将询问排序过,所以更新的树状数组所求出的答案一定是对于当前右端点是合法的。
\(\\\)
\(Code\)
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define R register
#define N 500010
#define M 200010
using namespace std;
int n,m,clr[N],ans[M],last[1000010];
struct tasks{int l,r,num,ans;}tsk[M];
struct BIT{
int c[N];
BIT(){memset(c,0,sizeof(c));}
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int k){
for(R int i=x;i<=n;i+=lowbit(i)) c[i]+=k;
}
inline int sum(int x){
int res=0;
for(R int i=x;i;i-=lowbit(i)) res+=c[i];
return res;
}
}bit;
inline int rd(){
int x=0;
char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x;
}
inline bool cmp(tasks a,tasks b){
return (a.r==b.r)?(a.l<b.l):(a.r<b.r);
}
int main(){
n=rd();
for(R int i=1;i<=n;++i) clr[i]=rd();
m=rd();
for(R int i=1;i<=m;++i) {
tsk[i].l=rd();
tsk[i].r=rd();
tsk[i].num=i;
}
sort(tsk+1,tsk+1+m,cmp);
int now=1;
for(R int i=1;i<=n;++i){
bit.add(i,1);
if(last[clr[i]]) bit.add(last[clr[i]],-1);
last[clr[i]]=i;
while(i==tsk[now].r){
tsk[now].ans=bit.sum(i)-bit.sum(tsk[now].l-1);
++now;
}
if(now>m)break;
}
for(R int i=1;i<=m;++i) ans[tsk[i].num]=tsk[i].ans;
for(R int i=1;i<=m;++i) printf("%d\n",ans[i]);
return 0;
}
\(\\\)
\(Extend\)
将询问改为,求区间内至少出现过两次的不同数字个数。
\(\\\)
- 注意到只有询问区间内出现两次数字才是有效的,但仿照之前的写法如果直接标记第二次出现的数,并取消第一次出现的数却会出错,是因为可能所谓的第一次出现的数并不在询问区间里,而所谓的第二个数却被算进了答案。
- 于是做法就改为记录两次上一个出现的位置,每次出现一个数将两次前出现该数的位置\(-1\),一次前出现的位置\(+1\)即可,这样能保证一个数只算了一次,并且出现两次的数一定打过标记。
\(\\\)
\(Code\)
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 2000010
#define R register
#define gc getchar
using namespace std;
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
int n,c,m,s[N],lst1[N],lst2[N],ans[N];
struct query{int l,r,num;}q[N];
inline bool cmp(query x,query y){
return x.r==y.r?x.l<y.l:x.r<y.r;
}
struct BIT{
int c[N];
BIT(){memset(c,0,sizeof(c));}
inline int lowbit(int x){return x&-x;}
inline void add(int p,int x){
for(;p<=n;p+=lowbit(p)) c[p]+=x;
}
inline int sum(int p){
int res=0;
for(;p;p-=lowbit(p)) res+=c[p];
return res;
}
}bit;
int main(){
n=rd(); c=rd(); m=rd();
for(R int i=1;i<=n;++i) s[i]=rd();
for(R int i=1;i<=m;++i){
q[i].l=rd(); q[i].r=rd(); q[i].num=i;
}
sort(q+1,q+1+m,cmp);
for(R int i=1,top=1;i<=n;++i){
if(lst2[s[i]]) bit.add(lst2[s[i]],-1);
if(lst1[s[i]]){bit.add(lst1[s[i]],1);}
lst2[s[i]]=lst1[s[i]]; lst1[s[i]]=i;
while(q[top].r==i){
ans[q[top].num]=bit.sum(i)-bit.sum(q[top].l-1);
++top;
}
}
for(R int i=1;i<=m;++i) printf("%d\n",ans[i]);
return 0;
}
[ SDOI 2009 ] HH的项链 & [ HEOI 2012 ] 采花的更多相关文章
- [BZOJ 2743] [HEOI 2012] 采花
Description 萧芸斓是Z国的公主,平时的一大爱好是采花.今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花.花园足够大,容纳了 \(n\) 朵花,花有 \(c\) 种颜色(用整数 \ ...
- [SDOI 2009]HH的项链
Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝 壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此,他的项链变得 ...
- 解题:HEOI 2012 采花
题面 题外话:LYD说他当时看错题了,考场爆零了,然后有了作诗这道题=.= 离线处理询问,按右端点递增排序,然后对于每种花$flw[i]$,我们求一个$pre[flw[i]]$表示这种花上一次出现的位 ...
- [HEOI 2012] 采花
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2743 [算法] 首先预处理nxt[]数组 , 其中 , nxt[i]表示下一个和i号 ...
- SDOI HH的项链 HEOI采花
题目大意: SDOI求一个区间内只出现一次的数的个数.多组询问. HEOI 求一个区间内出现至少两次的数的个数.多组询问. SDOI HH'neckplace如果每次询问都是1..r的话,那么我们只要 ...
- BZOJ 1878 SDOI 2009 HH项链 树状数组 + 脱机处理
标题效果:一些珠子项链.珠具有不同的颜色.我们问了很多次有多少种不同的颜色有过一段范围. 思考:这个问题让我学会聪明的离线实践.按左端点排序问题.加工出来的位置每种颜色首次出现.每一种颜色的下一次出现 ...
- [SDOI 2009]HH去散步
Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又 ...
- [BZOJ 1875] [SDOI 2009] HH去散步【矩阵乘法】
题目链接:BZOJ - 1875 题目分析: 这道题如果去掉“不会立刻沿着刚刚走来的路走回”的限制,直接用邻接矩阵跑矩阵乘法就可以了.然而现在加了这个限制,建图的方式就要做一些改变.如果我们把每一条边 ...
- sdoi 2009 HH去散步 矩阵乘
如果没有题里的"不会立刻沿着刚刚走来的路走回"限制,那么直接矩乘计算k步的方案数 但加了这个限制,就不能以点来矩乘了,考虑边数<=60,如果以边建邻接矩阵呢?? 先拆边,再把 ...
随机推荐
- 使用lombok提高编码效率-----不用写get set
使用lombok提高编码效率-----不用写get set https://blog.csdn.net/v2sking/article/details/73431364
- 九度oj 题目1066:字符串排序
题目1066:字符串排序 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:6487 解决:2670 题目描述: 输入一个长度不超过20的字符串,对所输入的字符串,按照ASCII码的大小从小到 ...
- 九度oj 题目1473:二进制数
题目描述: 大家都知道,数据在计算机里中存储是以二进制的形式存储的. 有一天,小明学了C语言之后,他想知道一个类型为unsigned int 类型的数字,存储在计算机中的二进制串是什么样子的. 你能帮 ...
- 转载 - JSONObject简介
出处: http://www.cnblogs.com/java-pan/archive/2012/04/07/JSONObject.html JSONObject简介 本节摘要:之前对JSON做了 ...
- Linux command2
. CentOS 想查看哪个port开了,却提示命令无效 # yum -y install net-tools 2. How to install "wget" command i ...
- codevs——2645 Spore
2645 Spore 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 某陈和某Y 最近对一个游戏着迷.那 ...
- 定义Portal显示规则
Defining Portal Display Rules Use You use the Portal Display Rules editor to create and edit rule co ...
- WCF 配置文件中的MaxStringContentLength & MaxReceivedMessageSize
中午测试员在测试系统模块时发现无法通过WCF从服务器下载数据,检查配置文件后,建议开发人员修改站点的WEB.CONFIG文件,具体修改对比如下: 旧的: <binding name=" ...
- C++学习之命名空间
在C++中,命名空间(namespace)的目的是为了防止名字冲突.每个命名空间是一个作用域,在所有命名空间之外,还存在一个全局命名空间(global namespace),全局命名空间以隐式的方式声 ...
- MVC异常过滤器 (错误页)
控制器 using System; using System.Collections.Generic; using System.Linq; using System.Web; using Syste ...