1. 程式人生 > >【[HEOI2012]採花】

【[HEOI2012]採花】

\(HH\)的項鍊加強版,資料範圍和題意都加強了

題意大概:給出n個數,求區間出現次數>=2的數的個數。

一眼莫隊,可是我還不會莫隊啊

那就樹狀陣列吧

回憶一下\(HH\)的項鍊,套路差不多,那道題我們維護的是每一種顏色最後出現的位置,因為根據其最後出現的位置我們就可以判斷其是否在區間裡

而判斷這道題也很簡單,我們維護每一個顏色倒數第二次出現是在什麼位置,這樣就能判斷其是否出現次數大於等於二了

還是離線+樹狀陣列就可以啦

程式碼

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define re register
#define lowbit(x) ((x)&(-x))
#define maxn 2000005
inline int read()
{
    char c=getchar();
    int x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x;
}
int c[2][maxn];
int n,m,T;
struct Ask
{
    int l,r,rk;
}q[maxn];
inline int cmp(Ask K,Ask M)
{
    return K.r<M.r;
}
inline void add(int x,int o,int val)
{
    for(re int i=x;i<=n;i+=lowbit(i))
        c[o][i]+=val;
}
inline int ask(int x,int o)
{
    int ans=0;
    for(re int i=x;i;i-=lowbit(i))
        ans+=c[o][i];
    return ans;
}
int a[maxn],pre[maxn],col_p[maxn],Ans[maxn];
int main()
{
    n=read(),T=read(),m=read();
    for(re int i=1;i<=n;i++) a[i]=read();
    for(re int i=1;i<=m;i++)
        q[i].l=read(),q[i].r=read(),q[i].rk=i;
    std::sort(q+1,q+m+1,cmp);
    for(re int i=1;i<=n;i++)
        pre[i]=col_p[a[i]],col_p[a[i]]=i;
    int now=1;
    for(re int i=1;i<=n;i++)
    {
        if(!pre[i]) add(i,0,1);
        else
        {
            if(!pre[pre[i]]) add(i,0,1),add(pre[i],1,1),add(pre[i],0,-1);
            else
            {
                add(i,0,1),add(pre[i],0,-1);
                add(pre[i],1,1),add(pre[pre[i]],1,-1);
            }
        }
        while(i==q[now].r) Ans[q[now].rk]=ask(q[now].r,1)-ask(q[now].l-1,1),now++;
    }
    for(re int i=1;i<=m;i++)
        printf("%d\n",Ans[i]);
    return 0;
}