欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-27 16:25:21
...

这道题想了很久,发题解是为了理解的更深刻一点。。。(管理放我过好嘛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<k.x){
            add(last[j]);
            j++;
        }
        ans[k.id]=sum(k.y)-sum(k.x-1);
    }

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


#include<bits/stdc++.h>
#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<int,int>
#define yxdl(qt) priority_queue<int,vector<int>,greater<int> >qt
#define xgd(qt)  priority_queue<int,vector<int>,less<int> >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] );
    }
}