[题解]luogu_P1972_HH的项链(树状数组/莫队

原来就做过的题,顺便再看一下写个题解,理解不够深刻

核心:对于重复出现的数字我们只计算最后出现的那个,其实和计数的一个技巧非常像就是对于可能重复计算的只计算有某特点的那个,防止算重,比较抽象以后再说吧

所以这题用树状数组记录每个位置的数字是否第一次出现,每次区间查询

原来的代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=500010;
int n,m;
int a[maxn],t[maxn],v[2*maxn];
int nxt[2*maxn];//數字i在此後第一次出現的位置 
struct node{
    int l,r,id;
}qq[maxn];int cnt;
int ans[maxn];
inline int read()
{
    int ret=0,fix=1;char ch;
    while(!isdigit(ch=getchar())) fix=ch=='-'? -1:fix;
    do ret=(ret<<1)+(ret<<3)+ch-'0';
    while(isdigit(ch=getchar()));
    return ret*fix;
}
inline void add(int x,int num)
{
    while(x<=n){
        t[x]+=num;
        x+=lowbit(x);
    }
}
inline int query(int x)
{
    int ans=0;
    while(x>0){
        ans+=t[x];
        x-=lowbit(x);
    }
    return ans;
}
bool cmp(node a,node b)
{
    if(a.r!=b.r)return a.r<b.r;
    else return a.l<b.l;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    m=read();
    for(int i=1;i<=m;i++){
        qq[++cnt].l=read();
        qq[cnt].r=read();
        qq[cnt].id=i;
    }
    sort(qq+1,qq+1+m,cmp);
//    for(int i=n;i>=1;i--){
//        if(!v[a[i]])nxt[i]=n+1;
//        else nxt[i]=v[a[i]];
//        v[a[i]]=i;
//    }
//    for(int i=1;i<=m;i++){
//        for(;j<q[i].x;j++)
//        add(nxt[j],1);
//        ans[qq[i].id]=query(q[i].r)-query(q[i].l-1);
//    }
    int last=1;
    for(int i=1;i<=m;i++){
        for(int j=last;j<=qq[i].r;j++){
            if(nxt[a[j]])add(nxt[a[j]],-1);
            add(j,1);
            nxt[a[j]]=j;
        }
        last=qq[i].r+1;
        ans[qq[i].id]=query(qq[i].r)-query(qq[i].l-1);
    }
    for(int i=1;i<=m;i++)
    printf("%d\n",ans[i]);
}

 

posted @ 2019-09-11 10:00  羊肉汤泡煎饼  阅读(148)  评论(0编辑  收藏  举报