P1972 [SDOI2009]HH的项链

暑假刚学树状数组时就看了这个题,当时挺无头绪的。之后在昨天写了一道区间查询不同个数的模板题,转头发现这个题也是个模板......

思路:用树状数组维护一个长度为输入总数长度的数组,然后向树状数组输入每一个位置的值,从该位置开始向上更新,每个数组值++,如果这个值在之前最近的位置出现过,所对应的最近位置向上更新,每个数组值--。向下查询的时候返回从下标1位置到当前查询位置所有的不同个数,query(r)-query(l-1)所得到的就是整个区间之内所有不同的数的个数。现在剩下的就是要离线一下,把查询按r的顺序从小到大排一遍,边查询边更新树状数组。

树状数组难的还是想着怎么维护啊。

 

代码写的特别乱,但还是水过了

#include <set>
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int Maxn=1000010;
int pos[Maxn],tree[Maxn],num[Maxn],n,ans[Maxn];

struct st
{
    int l,r,flag,ans;
}q[Maxn];

bool cmp(st a, st b)
{
    return a.r<b.r;
}

void update(int x,int y,int k)
{
    if(k==1)
    {
        for(;x<=n;x+=x & (-x)) tree[x]++;
    }
    if(k==2)
    {
        for(;x<=n;x+=x & (-x)) tree[x]--;
        for(;y<=n;y+=y & (-y)) tree[y]++;
    }
}

int query(int x)
{
    int ans=0;
    for(;x>0;x-=x & (-x)) ans+=tree[x];
    return ans;
}

int main()
{
    int m; scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&num[i]);
    scanf("%d",&m); int l,r;
    for(int i=1;i<=m;i++) {scanf("%d%d",&l,&r); q[i].l=l; q[i].r=r; q[i].flag=i;}
    sort(q+1,q+m+1,cmp); int last=1;
    for(int i=1;i<=m;i++)
    {
        int j; //cout<
        for(j=last;j<=q[i].r;j++)
        {
            int temp=num[j];
            if(!pos[temp]) update(j,pos[temp],1);
            if(pos[temp]) update(pos[temp],j,2);
            pos[temp]=j;
        }
        //for(int i=1;i<=n;i++) cout<
        last=j;
        //cout<//cout<
        if(q[i].r==q[i].l) ans[q[i].flag]=1;
        else ans[q[i].flag]=query(q[i].r)-query(q[i].l-1);
        //if(q[i].r==q[i].l) cout<<1<//else cout<
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}

 

你可能感兴趣的:(P1972 [SDOI2009]HH的项链)