[ 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,如果以边建邻接矩阵呢?? 先拆边,再把 ...
随机推荐
- 【05】JSON笔记
[05]笔记 尽管有许多宣传关于 XML 如何拥有跨平台,跨语言的优势,然而,除非应用于 Web Services,否则,在普通的 Web 应用中,开发者经常为 XML 的解析伤透 ...
- 我安装android studio的过程与经历
虽然android studio已经出来两年多了,但是我一直都没真正用过.之前用Eclipse还算用得挺好.我并不是一个专职的android开发者,我是个游戏开发者,打包的时候要用到android.不 ...
- CodeForcesGym 100753E Change of Scenery
Change of Scenery Time Limit: 10000ms Memory Limit: 262144KB This problem will be judged on CodeForc ...
- [luoguP2858] [USACO06FEB]奶牛零食Treats for the Cows(DP)
传送门 f[i][j][k] 表示 左右两段取到 i .... j 时,取 k 次的最优解 可以优化 k 其实等于 n - j + i 则 f[i][j] = max(f[i + 1][j] + a[ ...
- Codeforces Round #244 (Div. 2)
今天是水题集啊.... A. Police Recruits time limit per test 1 second memory limit per test 256 megabytes inpu ...
- 4种OSS的应用架构及核心技术
基础型 架构描述:OSS作为文件存储源,用户上传下载数据均经过ECS与OSS通信. 解决用户问题:文件空间大,ECS磁盘存储空间有限:多ECS间无法同步数据. 适用场景描述:文件较多,但文件调 ...
- 条款45: 弄清C++在幕后为你所写、所调用的函数
如果你没有声明下列函数,体贴的编译器会声明它自己的版本.这些函数是:一个拷贝构造函数,一个赋值运算符,一个析构函数,一对取址运算符.另外,如果你没有声明任何构造函数,它也将为你声明一个缺省构造函数.所 ...
- MVC路由中特殊URL匹配规则
*匹配*用来匹配URL剩余部分 贪婪匹配规则贪婪匹配会找到最后一个符合条件的“字面量”为止
- 阿牛的EOF牛肉串-记忆化搜索或动态规划
C - 阿牛的EOF牛肉串 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submi ...
- input屏蔽历史记录 ;function($,undefined) 前面的分号是什么用处 JSON 和 JSONP 两兄弟 document.body.scrollTop与document.documentElement.scrollTop兼容 URL中的# 网站性能优化 前端必知的ajax 简单理解同步与异步 那些年,我们被耍过的bug——has
input屏蔽历史记录 设置input的扩展属性autocomplete 为off即可 ;function($,undefined) 前面的分号是什么用处 ;(function($){$.ex ...