Luogu P1972 [SDOI2009]HH的项链

清新自然凶猛的数据结构题,都是套路

我们可以考虑离线做,先把区间按右端点从小到大排序

首先注意到一种贝壳如果在一段中出现超过1次,那么它在前面或后面就无关紧要了

举一个例子:

对于数列1 2 3 1如果我的右端点已经扫描到第四位了,那么第一位的1就可以删掉了(因为按右端点排了序)

所以我们开树状数组维护一个位置上是否有有效的颜色,即对于上一个例子2,3,4位上是有有效的颜色的

然后对于每一个操作,我们求出x,y这段区间内1的个数即可,树状数组减一发即可

具体看代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=500005,M=200005,MAX_NUM=1000005;
struct ques
{
    int x,y,num;
}q[M];
int tree[N],a[N],num[MAX_NUM],ans[M],n,m,now;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch=tc();
    while (ch<'0'||ch>'9') ch=tc();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
inline void write(int x)
{
    if (x/10) write(x/10);
    putchar(x%10+'0');
}
inline bool comp(ques a,ques b)
{
    return a.y<b.y;
}
inline int lowbit(int x)
{
    return x&(-x);
}
inline void add(int x,int y)
{
    while (x<=n)
    {
        tree[x]+=y;
        x+=lowbit(x);
    }
}
inline int get(int x)
{
    int tot=0;
    while (x)
    {
        tot+=tree[x];
        x-=lowbit(x);
    }
    return tot;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i;
    for (read(n),i=1;i<=n;++i)
    read(a[i]); 
    for (read(m),i=1;i<=m;++i)
    read(q[i].x),read(q[i].y),q[i].num=i;
    sort(q+1,q+m+1,comp);
    for (now=1,i=1;i<=m;++now)
    {
        if (!num[a[now]]) add(now,1),num[a[now]]=now; else add(num[a[now]],-1),num[a[now]]=now,add(now,1);
        while (now==q[i].y&&i<=m)ans[q[i].num]=get(q[i].y)-get(q[i].x-1),++i;
    }
    for (i=1;i<=m;++i)
    write(ans[i]),putchar('
');
    return 0;
}
原文地址:https://www.cnblogs.com/cjjsb/p/8893522.html