[SDOI2009]HH的项链

本文探讨了一道经典算法题目,讲解了如何使用树状数组和主席树等数据结构来解决区间内唯一元素的计数问题,提供了详细的代码实现及优化思路。

传送门

Solution

这是一道很经典的题目吖

莫队的话,在洛谷上吸吸氧就能过了

其实这题是由很多做法的吧

我们一种颜色显然只有在它第一次出现的时候有贡献

或者说,我们让它在最后一次出现的时候有贡献

然后把按照r从小到大排序,用树状数组维护每个点最后一次出现的位置(权值为1,之前的为0)

然后区间求和就行啦

主席树也能做?

这下我们让每个数第一次出现有贡献~

对于每个位置,记下该数上次出现的位置,如果小于l,那么它是第一次出现的

维护一个last的权值线段树,然后每次查询区间中小于l的数


Code 


#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 500005
int col[MN],l,r,pos[MN];
struct ques{
    int l,r,id;
    bool operator<(const ques&x) const{return pos[l]^pos[x.l]?pos[l]<pos[x.l]:r<x.r;}
}q[MN];
int num[MN<<1],ans,print[MN];
int main()
{
    register int n,m,i,T;
    n=read();
//  T=(int)(sqrt(n));
    T=1500;
    for(i=1;i<=n;++i) col[i]=read(),pos[i]=(i+1)/T+1;
    m=read();
    for(i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;
    std::sort(q+1,q+m+1);
    register int L,R;
    for(L=1,R=0,i=1;i<=m;++i)
    {
        for(;R<q[i].r;++R) ans+=(!num[col[R+1]]),num[col[R+1]]++;
        for(;R>q[i].r;--R) ans-=(num[col[R]]==1),num[col[R]]--;
        for(;L>q[i].l;--L) ans+=(!num[col[L-1]]),num[col[L-1]]++;
        for(;L<q[i].l;++L) ans-=(num[col[L]]==1),num[col[L]]--;
        print[q[i].id]=ans; 
    }
    for(i=1;i<=m;++i) printf("%d\n",print[i]);
}



Blog来自PaperCloud,未经允许,请勿转载,TKS!

转载于:https://www.cnblogs.com/PaperCloud/p/10166288.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值