BaoBao Loves Reading ZOJ - 4117 (思维/求区间不同种类数)

对于每个数,我们记录上一次这个数出现的位置;

计算之间间隔了几个不同数x,如果一个桌子的容量>=x,那我们不用把书放回,如果桌子的容量<x,那么我们只能把书放回去这本书

定义 t[] 每次使t[x]++,也就是对于容量小于 x的桌子每次都要从新取书,对于大于等于x的桌子不用

最后累加起来,最后结果就是

n-(t[1]+...+t[i]);

 

对于求区间不同种类的数字 可以用树状数组 莫队 主席树;

  

#include<bits/stdc++.h>

using namespace std;

const int maxn=2e5+10;
const double EPS=1e-12;

#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long

int tree[maxn];

int ans[maxn],pre[maxn];

int vis[maxn],arr[maxn];

int n;

int lowbit(int x)
{
    return x&(-x);
}

void add(int x,int val)
{
    while(x<=n)
    {
        tree[x]+=val;
        x+=lowbit(x);
    }
    //cout<<"hereadd"<<endl;
}

int sum(int x)
{
    int temp=0;
    while(x>0)
    {
        temp+=tree[x];
        x-=lowbit(x);
    }
    //cout<<"heresum"<<endl;
    return temp;
}

void init()
{
    mem(arr,0);
    mem(vis,0);
    mem(tree,0);
    mem(ans,0);
    mem(pre,0);
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        init();
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>arr[i];
            pre[i]=vis[arr[i]];
            vis[arr[i]]=i;
        }

        //cout<<"here"<<endl;

        for(int i=1;i<=n;i++)
        {
            if(pre[i])
            {
                add(pre[i],-1);
                add(i,1);
                int temp=sum(i)-sum(pre[i]-1);
                ans[temp]++;
            }
            else add(i,1);
        }

        //cout<<"here"<<endl;

        int tot=0;
        for(int i=1;i<=n;i++)
        {
            tot+=ans[i];
            if(i!=1) cout<<" ";
            cout<<n-tot;
        }
        cout<<"\n";
    }


    return 0;
}

 

posted @ 2019-05-18 20:00  Minun  阅读(258)  评论(0编辑  收藏  举报