HH的项链
题目来源 HH的项链-洛谷
思路 初学树状数组,在洛谷上刷道树状数组模板题,详细见代码注释,有出错的地方还请大神指正 =)
要清楚一点,树状数组的那棵“树”标号是按中序遍历(左根右)标的(我一开始就是这个没有想通)
传送门
AC代码
//模板题 #include<iostream> #include<algorithm> #define N 1000001 using namespace std; int a[N],tree[N],flag[N],ans[N],n,m,pos=1; //a存储原数组 //tree为树状数组记录贡献值 //flag用于标记是否已经出现某种颜色 //ans输出最终答案(离线) //pos记录计算颜色数的起始位置 struct t{ int l;//查询左端 int r;//查询右端 int pl;//记录输入顺序,直接输出答案会寄 }q[N]; int lowbit(int num){//核心代码x1 return num&(-num); } void Add(int num,int point){//核心代码x2: 单点数值修改 while(num<=n){ tree[num]+=point; num+=lowbit(num); } } int Sum(int num){//核心代码x3: 用于求1-num的前缀和 int sum=0; while(num!=0){ sum+=tree[num]; num-=lowbit(num); } return sum; } bool cmp(t A,t B){ return A.r<B.r;//按查询的右端排序 } int main(){ ios::sync_with_stdio(0); cin>>n; for(int i=1;i<=n;i++) cin>>a[i];//读入原数组 cin>>m; for(int i=1;i<=m;i++){ cin>>q[i].l>>q[i].r;//读入查询的左右端点 q[i].pl=i;//记录输入顺序 } sort(q+1,q+m+1,cmp); for(int i=1;i<=m;i++){ for(int j=pos;j<=q[i].r;j++){ if(flag[a[j]]) Add(flag[a[j]],-1); //计算贡献:从右往左相同颜色第一次出现标记为1,其余为0 //更新过程:如果出现过相同颜色,将原来的全部-1 Add(j,1);//当前项+1,作为该种颜色的贡献值 flag[a[j]]=j;//标记该颜色已经出现 } pos=q[i].r+1;//移动下标,为下一次查询做准备 ans[q[i].pl]=Sum(q[i].r)-Sum(q[i].l-1); //1~r的贡献总和减去1~l-1的贡献总和即为l~r出现的颜色种数,前准和思想 } for(int i=1;i<=m;i++) cout<<ans[i]<<'\n';//按原来顺序输出结果 return 0; } /*代码模拟 查询排序: 1 2 3 5 2 6 第一个查询: 1 1 1 2 3 4 3 5 1+1=2 第二个查询: 1 1 0 1 1 1 2 3 4 3 5 0+1+1=2 第三个查询: 1 1 0 1 1 1 1 2 3 4 3 5 1+0+1+1+1=4 */