题解 P1972 【[SDOI2009]HH的项链】
[SDOI2009]HH的项链
Description
HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
Solution
- Solution1: 莫队.
不会 - Solution2: 离线, 离散化,链表,树状数组.
首先, 可以将颜色离散化.因为颜色从
1-1000000 实在是太大了.namespace Map{ int rank[N]; int vis[P]; void init(){ for(int i=1;i<=n;++i)if(!vis[col[i]])s[++tot]=col[i],vis[col[i]]=true; sort(s+1,s+tot+1); for(int i=1;i<=tot;++i)rank[s[i]]=i; for(int i=1;i<=n;++i)s[i]=rank[col[i]]; } };其次, 将项链按颜色建链表, 如果有
\text{tot} 种颜色, 那就按坐标建\text{tot} 个链表.
namespace List{
struct Node{
int v,nxt;
}e[N];
int head[M],tail[M],pos[M],cnt;
void AddEdge(int color,int posit){
if(!head[color]){head[color]=++cnt;e[cnt]=(Node){posit,0};tail[color]=head[color]=cnt;;}
else e[tail[color]].nxt=++cnt,e[cnt]=(Node){posit,0},tail[color]=cnt;
}
int Next(int col,int l){int i;for(i=pos[col]?pos[col]:head[col];e[i].v<l&&i;i=e[i].nxt);pos[col]=i;if(e[i].v)return e[i].v;else return n+1;}
};using namespace List;
然后将查询按左端点从小到大排序.
struct Query{
int l,r,id;
bool operator<(const Query& b)const{return l<b.l;}
}q[M];
在每个查询中, 找出从左端点
namespace BIT{
int t[N];
int lowbit(int i){return i&(-i);}
void Add(int p,int c){int i=p;while(i<=n)t[i]+=c,i+=lowbit(i);}
int query(int r){int i=r,ans=0;while(i)ans+=t[i],i-=lowbit(i);return ans;}
int QUEry(int l,int r){return query(r)-query(l-1);}
};using namespace BIT;
还有一个问题是如何快速从一个查询过度到另一个查询? 因为从
- 可以枚举每一种颜色是否需要更新第一次在
[l,n] 出现的坐标, 复杂度O(km) (k为颜色数量).结果:T成沙茶. - 直接枚举
[l,l') 之内的颜色是否需要更新, 均摊复杂度O(n) .结果:通过
Code
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cctype>
#define M 200005
#define N 500005
#define P 1000005
#define inf 0x3f3f3f3f
using namespace std;
int read(){
char ch=getchar();int s=0;
for(;!isdigit(ch);ch=getchar());
for(s=0;isdigit(ch);s=s*10+ch-'0',ch=getchar());
return s;
}
int col[N],s[N];
int Answer[M];
int n,m,tot;
/*******************************************************************/
struct Query{
int l,r,id;
bool operator<(const Query& b)const{return l<b.l;}
}q[M];
/*******************************************************************/
namespace Map{
int rank[N];
int vis[P];
void init(){
for(int i=1;i<=n;++i)if(!vis[col[i]])s[++tot]=col[i],vis[col[i]]=true;
sort(s+1,s+tot+1);
for(int i=1;i<=tot;++i)rank[s[i]]=i;
for(int i=1;i<=n;++i)s[i]=rank[col[i]];
}
};
/*******************************************************************/
namespace List{
struct Node{
int v,nxt;
}e[N];
int head[M],tail[M],pos[M],cnt;
void AddEdge(int color,int posit){
if(!head[color]){head[color]=++cnt;e[cnt]=(Node){posit,0};tail[color]=head[color]=cnt;}
else e[tail[color]].nxt=++cnt,e[cnt]=(Node){posit,0},tail[color]=cnt;
}
int Next(int col,int l){int i;for(i=pos[col]?pos[col]:head[col];e[i].v<l&&i;i=e[i].nxt);pos[col]=i;if(e[i].v)return e[i].v;else return n+1;}
};using namespace List;
/*******************************************************************/
namespace BIT{
int t[N];
int lowbit(int i){return i&(-i);}
void Add(int p,int c){int i=p;while(i<=n)t[i]+=c,i+=lowbit(i);}
int query(int r){int i=r,ans=0;while(i)ans+=t[i],i-=lowbit(i);return ans;}
int QUEry(int l,int r){return query(r)-query(l-1);}
};using namespace BIT;
/*******************************************************************/
int visit[N];
int main(){
scanf("%d",&n);int u,v,c;
for(int i=1;i<=n;++i)
col[i]=read();
Map::init();
for(int i=1;i<=n;++i)List::AddEdge(s[i],i);
scanf("%d",&m);
for(int i=1;i<=m;++i)q[i].l=read(),q[i].r=read();
for(int i=1;i<=m;++i)q[i].id=i;
sort(q+1,q+m+1);int po=0;
for(int i=1;i<=tot;++i)Add(Next(i,1),1);
for(int i=1;i<=m;++i){
if(q[i].l>q[i-1].l){
for(int j=q[i-1].l;j<q[i].l;++j)
if(visit[s[j]]!=i){
Add(Next(s[j],q[i].l),1),visit[s[j]]=i;
}
}
Answer[q[i].id]=QUEry(q[i].l,q[i].r);
}
for(int i=1;i<=m;++i)
printf("%d\n",Answer[i]);
return 0;
}