简单的爱心效果

HH的项链

题目来源 HH的项链-洛谷

思路 初学树状数组,在洛谷上刷道树状数组模板题,详细见代码注释,有出错的地方还请大神指正 =)

要清楚一点,树状数组的那棵“树”标号是按中序遍历(左根右)标的(我一开始就是这个没有想通)

传送门

树状数组-百度百科

树状数组详解-CSDN

树状数组详解(1)-CSDN

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

*/ 
posted @ 2023-03-11 22:15  Light-Chaser  阅读(31)  评论(0编辑  收藏  举报
简单的爱心效果