[BZOJ] 1878: [SDOI2009]HH的项链
题意:给一个序列,多次询问一个区间内不同的数的个数。
不知道为什么主席树卡80分了..
感觉问不同数个数的题,都和next或者pre数组有关。
记pre[i]为val[i]上一次出现的位置,第一次出现则为0,我们将询问按右端点升序排序。
对于每个询问,处理出它和上次询问之间新增加的数,具体就是把pre删掉1,cur加上1。
之所以可以这样做,是因为我们只关心在一个区间内,某个数最靠右出现的位置。
询问排过序了,记得输出答案也要排序。
#include<algorithm> #include<iostream> #include<cstdio> using namespace std; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN=500005; int n,m; int val[MAXN]; int t[MAXN<<1]; int query(int x){ int ret=0; for(int i=x;i;i-=i&-i) ret+=t[i]; return ret; } void update(int x,int w){ if(x==0) return; for(int i=x;i<=n;i+=i&-i) t[i]+=w; } int pre[MAXN],pos[1000005]; int qx[MAXN],qy[MAXN],id[MAXN],ans[MAXN]; bool cmp(int x,int y){return qy[x]<qy[y];} int main(){ n=rd(); for(int i=1;i<=n;i++) { val[i]=rd(); } for(int i=1;i<=n;i++){ pre[i]=pos[val[i]]; pos[val[i]]=i; } m=rd(); for(int i=1;i<=m;i++){ qx[i]=rd();qy[i]=rd();id[i]=i; } sort(id+1,id+1+m,cmp); int j=1; for(int i=1;i<=m;i++){ int v=id[i]; for(;j<=qy[v];j++){ update(pre[j],-1); update(j,1); } ans[v]=query(qy[v])-query(qx[v]-1); } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9378112.html