题意:给出一个单词组成的序列 然后给出一堆的询问 问[l,r]之间有多少个不同的单词
解法:这一题要注意的就是先离散化单词 然后直接分块就可以了 判断条件也很好写 就是是否有出现新单词 或者已经计算在内的单词被删除了才会改变答案值
当然这一题如果用线段树也是可以做的 大概还要维护一个双端队列吧
#include<map>
#include<cstdio>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 111111
#define sqr 111
map<string,int>mp;
int ll[maxn],rr[maxn],cnt[maxn],id[maxn],a[maxn],ans[maxn];
int co;
int cmp(int x,int y){
if(ll[x]/sqr==ll[y]/sqr){
return rr[x]<rr[y];
}else return ll[x]<ll[y];
}
int n,m;
char s[2222];
int main(){
while(~scanf("%d%d",&n,&m)){
mp.clear();co=0;
for(int i=0;i<n;++i){
scanf("%s",s);
if(!mp[s]){
a[i]=++co;
mp[s]=co;
}else a[i]=mp[s];
}
for(int i=0;i<m;++i){
scanf("%d%d",&ll[i],&rr[i]);--ll[i],--rr[i];
id[i]=i;
}
memset(cnt,0,sizeof cnt);
sort(id,id+m,cmp);
int tot=0,nowl=0,nowr=-1;
for(int i=0;i<m;++i){
int l=ll[id[i]],r=rr[id[i]];
while(nowr<r){tot+=(++cnt[a[++nowr]]==1?1:0);}
while(nowl>l){tot+=(++cnt[a[--nowl]]==1?1:0);}
while(nowr>r){tot-=(--cnt[a[nowr--]]==0?1:0);}
while(nowl<l){tot-=(--cnt[a[nowl++]]==0?1:0);}
ans[id[i]]=tot;
}
for(int i=0;i<m;++i)printf("%d\n",ans[i]);
}
return 0;
}