HH的项链——题解

题目描述

image

直接求解会导致不同贝壳在上个区间算过但这个区间没标记的情况,所以在求解时要把上个区间的标记转移到这个区间
转移前先右边界由小到大排序,然后转移上个右边界到这个右边界的标记,同时记录上个标记出现的地方,方便转移
下面附代码

solution

#include<bits/stdc++.h>
using namespace std;
int a[10000000],c[10000000],ans[10000000],n,t,l,r,now;
int vis[10000000];
int lowbit(int x){
	return x&(-x);
} 
void add(int i,int k){
	while(i<=1e6){
		c[i]+=k;
		i+=lowbit(i);
	}
}
int getsum(int i){
	int res=0;
	while(i>0){
		res+=c[i];
		i-=lowbit(i);
	}
	return res;
}
struct lsx{
	int l,r,data;
}m[10000000];
bool cmp(lsx aa,lsx b){
	return aa.r<b.r;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	scanf("%d",&t);
	for(int i=1;i<=t;i++){
		scanf("%d%d",&m[i].l,&m[i].r);
		m[i].data=i;
	}
	sort(m+1,m+t+1,cmp);
	now=1;
	for(int i=1;i<=t;i++){
		for(int j=now;j<=m[i].r;j++){
			if(vis[a[j]]) add(vis[a[j]],-1);//删除上个区间的标记,防止前缀和多算
			add(j,1);
			vis[a[j]]=j;// 上一次这个数出现位置; 
			//循环为了将前面出现过的数的标记转移到所求区间内,再树状数组求前缀和; 
		}	
		now=m[i].r+1;
		ans[m[i].data]=getsum(m[i].r)-getsum(m[i].l-1);
	}
	for(int i=1;i<=t;i++){
		printf("%d\n",ans[i]);
	}
    return 0;
}
posted @ 2024-02-18 14:33  _君の名は  阅读(45)  评论(7编辑  收藏  举报