1. 程式人生 > 實用技巧 >P1972 [SDOI2009]HH的項鍊

P1972 [SDOI2009]HH的項鍊

P1972 [SDOI2009]HH的項鍊

原題地址:

這題看起來可以用莫隊做,本來想水一下的,然而我逛了一圈題解發現資料被加強了。

我稍微想了一下主席樹,感覺好像維護起來沒什麼用,可能是我太菜了。

Std:


個人的理解

其實這種想法就是在進行一種去重(消去重複的影響),讓統計變成最簡單的區間求和

既然我們區間顏色重疊會影響統計,那麼我們只要記錄當前最有效的顏色即可,區間右端點的排序保證了這種有效性。

Code:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 1000305
#define minn -105
#define ll long long int
#define ull unsigned long long int
#define uint unsigned int
inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'|ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans;
    return ans;
}
struct Query
{
    int l,r,id;
    bool operator<(const Query& sec)const
    {
        return r<sec.r;
    }
}q[maxn];

int tree[maxn];
int a[maxn],ans[maxn],pos[maxn];
int n,m;
void renew(int x,int k)
{
    for(;x<=n;x+=(x&-x))tree[x]+=k;
}
int cal(int x)
{
    int t=0;
    for(;x;x-=(x&-x))t+=tree[x];
    return t;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
    }
    m=read();
    for(int i=0;i<m;i++)
    {
        q[i].l=read(),q[i].r=read();q[i].id=i;
    }
    sort(q,q+m);
    int cur=0;
    for(int i=0;i<m;i++)
    {
        while(cur<q[i].r)
        {
            cur++;
            if(pos[a[cur]]!=0)renew(pos[a[cur]],-1);
            renew(cur,1);
            pos[a[cur]]=cur;
        }
        ans[q[i].id]=cal(q[i].r)-cal(q[i].l-1);
    }

    for(int i=0;i<m;i++)
    {
        cout<<ans[i]<<"\n";
    }
    return 0;
}