洛谷P1972 【[SDOI2009]HH的项链】

这道题想了很久,发题解是为了理解的更深刻一点。。。(管理放我过好嘛qwq)


步入正题:这道题应该是很多做法,我选择的是离线+树状数组。

首先输入数组。用fisrt数组先记录元素最开始出现的位置,对应的每一个树状数组的位置add一下(树状数组洛谷也有模板题的了解一下就ok啦)。

rep(i,1,n){//for循环的意思(1,n)闭区间
        scanf("%d",&a[i]);
        if(!first[a[i]]){
            first[a[i]]=i;
            add(i);//若第一次出现 则在树状数组中add。
        }
    }

然后倒着更新一遍数组,对每个元素用last数组记录当前下标元素的下一个出现的位置(可以模拟一遍就理解了)

per(i,n,1){//还是for循环(n,1)
        last[i]=first[a[i]];
        first[a[i]]=i;//last数组记录当前元素 下一次出现的位置。
    }

接下来就是存一下询问啦。用vector存结构体应该快一点,结构体用左端点为关键字进行sort排序。

    struct uzi{//全局的结构体,id为询问的序号
        int x,y,id;
        bool operator <(const uzi &a)const{
            return x<a.x;
         } 
    };

	vector<uzi> val;
    rep(i,0,m-1){
        int x,y;
        scanf("%d%d",&x,&y);
        val.push_back(uzi{x,y,i});//将询问存入
    }
    sort(val.begin(),val.end());//排序

接下来就是询问的处理啦(jd)

因为已经按左端点排序好了,所以 直接对树状数组动态更新,然后记录答案。这里用了一个j。当j比左端点小,就在j下标元素下个出现的位置对树状数组更新。(add)。。然后记录询问的结果就好啦。。。

for(auto k:val){
        while(j

然后直接输出每个询问的结果就做完啦。。。。。
贴下全部的代码


#include
#define swap(a,b) {a^=b;b^=a;a^=b}
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define PII pair
#define yxdl(qt) priority_queue,greater >qt
#define xgd(qt)  priority_queue,less >qt
#define INF 0x3f3f3f3f
#define lowbit(x)  x & -x
#define cs(s) freopen(s,"r",stdin)
#define debug(x) printf(" case-->%d ",x );
using namespace std;
typedef long long ll;
int a[500010],tree[500011],first[5000101],last[5100001],n,m,ans[510001];
struct uzi{
    int x,y,id;
    bool operator <(const uzi &a)const{
     	return x<a.x;
     } 
};
inline void add(int x){for(int i=x;i<=n;i+=lowbit(i))tree[i]+=1;}
inline int sum (int x){int ans=0;for(int i=x;i;i-=lowbit(i))ans+=tree[i];return ans;}
int main(){
    scanf("%d",&n);	
    rep(i,1,n){
        scanf("%d",&a[i]);
        if(!first[a[i]]){
            first[a[i]]=i;
            add(i);//若第一次出现 则在树状数组中add。
        }
    }
    per(i,n,1){
        last[i]=first[a[i]];
        first[a[i]]=i;//last数组记录当前元素 下一次出现的位置。
    }	
    scanf("%d",&m);
    vector<uzi> val;
    rep(i,0,m-1){
        int x,y;
        scanf("%d%d",&x,&y);
        val.push_back(uzi{x,y,i});//将询问存入
    }
    int j=1;
    sort(val.begin(),val.end());//排序
    for(auto k:val){
        while(j<k.x){
            add(last[j]);
            j++;
        }
        ans[k.id]=sum(k.y)-sum(k.x-1);
    }
    rep(i,0,m-1){
        printf("%d\n",ans[i] );
    }
}

你可能感兴趣的:(树状数组)