bzoj1878 [SDOI2009]HH的项链 主席树

来源:互联网 发布:淘宝一次破损补寄条款 编辑:程序博客网 时间:2024/05/19 12:24

题意:求区间不同自然数个数。
主席树裸题,记录一下last[a[i]]表示上一个数出现的位置,然后用主席树预处理差分一波,接着就可以直接做了。
还要在细一点的话,就是说,我在i这个位置上把ai加上去,然后在last[a[i]]的地方把它减掉。。

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=1e5+5;struct node{    int l,r,sum;}t[N*40];int root[N],a[N],tmp;int last[N*10],sz,n,q;inline void build(int &x,int l,int r){    x=++sz;    t[x].l=t[x].r=t[x].sum=0;    if (l==r)return;    int mid=(l+r)>>1;    build(t[x].l,l,mid);    build(t[x].r,mid+1,r);}inline void change(int &x,int pos,int last,int v,int l,int r){    x=++sz;    t[x]=t[last];    t[x].sum+=v;    if (l==r)return ;    int mid=(l+r)>>1;    if (pos<=mid)change(t[x].l,pos,t[last].l,v,l,mid);    else change(t[x].r,pos,t[last].r,v,mid+1,r);}inline int query(int pos,int x,int l,int r){    if (l==r)return t[x].sum;    int mid=(l+r)>>1;    if (pos<=mid)    return t[t[x].r].sum+query(pos,t[x].l,l,mid);    else return query(pos,t[x].r,mid+1,r);}int main(){    scanf("%d",&n);    memset(last,-1,sizeof(last));    fo(i,1,n)    {        scanf("%d",&a[i]);    }    build(root[0],1,n);    fo(i,1,n)    {        if (last[a[i]]==-1)            change(root[i],i,root[i-1],1,1,n);        else         {            change(tmp,last[a[i]],root[i-1],-1,1,n);            change(root[i],i,tmp,1,1,n);        }        last[a[i]]=i;    }    scanf("%d",&q);    while (q--)    {        int x,y;        scanf("%d%d",&x,&y);        printf("%d\n",query(x,root[y],1,n));    }}
原创粉丝点击