您的位置:首页 > 其它

bzoj1878 [SDOI2009]HH的项链 主席树

2017-10-23 22:19 323 查看
题意:求区间不同自然数个数。

主席树裸题,记录一下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
,a
,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));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: