luogu P4113 [HEOI2012]采花
题面传送门
和HH的项链那道题有点像。
将所有询问离线,按右端点排序。
维护每种颜色最近出现的和第二近出现的。当加入一种颜色时,将其第二近出现的删掉,使原来第一出现的变为第二出现的。
然后来了一个询问,查询比他大的数的个数就是答案,树状数组或线段树或平衡树随便维护一下就好了。
代码实现:
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,k,x,y,f[2000039],tot,pus,a[2000039],head=1,g1[2000039],g2[2000039],ans[2000039];
struct yyy{
int x,y,num;
}s[2000039];
inline bool cmp(yyy x,yyy y){return x.y<y.y;}
inline void read(int &x){
char s=getchar();x=0;
while(s<'0'||s>'9') s=getchar();
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
inline void print(int x){
if(x>9) print(x/10);
putchar(x%10+48);
}
inline void get(int x,int y){while(x<=n) f[x]+=y,x+=x&-x;}
inline int find(int x){int ans=0;while(x) ans+=f[x],x-=x&-x;return ans;}
int main(){
register int i;
read(n);read(k);read(m);
for(i=1;i<=n;i++) read(a[i]);
for(i=1;i<=m;i++) read(s[i].x),read(s[i].y),s[i].num=i;
sort(s+1,s+m+1,cmp);
for(i=1;i<=n;i++){
if(g1[a[i]]){
if(g2[a[i]])get(g2[a[i]],-1);
get(g1[a[i]],1);
}
g2[a[i]]=g1[a[i]];
g1[a[i]]=i;
while(s[head].y==i) ans[s[head].num]=find(n)-find(s[head].x-1),head++;
}
for(i=1;i<=m;i++) print(ans[i]),putchar('\n');
}

浙公网安备 33010602011771号