[HEOI2012]采花 BZOJ2743
分析:
听说主席树和莫队可以做,前者不想写,后者我不会...
我们考虑将询问离线,按照左端点排序,之后先处理好从1开始选的答案,之后枚举从1到n,之后依次删除nxt[i],添加nxt[nxt[i]],之后当询问左端点等于i的时候,更新答案。
附上代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <cmath> using namespace std; #define N 1000005 int n,m,a[N],vis[N],nxt[N],sum[N]; int find(int x) { int ret=0; for(int i=x;i;i-=i&-i)ret+=sum[i]; return ret; } void fix(int x,int c) { for(int i=x;i<N;i+=i&-i)sum[i]+=c; } struct node { int idx,l,r,ans; }q[N]; bool cmp(const node &a,const node &b){return a.l<b.l;} bool cmp1(const node &a,const node &b){return a.idx<b.idx;} int main() { scanf("%d%*d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(vis[a[i]])nxt[vis[a[i]]]=i; vis[a[i]]=i; } for(int i=1;i<=m;i++) { scanf("%d%d",&q[i].l,&q[i].r);q[i].idx=i; } sort(q+1,q+m+1,cmp); for(int i=1;i<=n;i++) { if(nxt[i])fix(nxt[i],1); if(nxt[nxt[i]]) fix(nxt[nxt[i]],-1); } int h=1; for(int i=1;i<=n;i++) { while(q[h].l==i)q[h].ans=find(q[h].r)-find(i-1),h++; if(nxt[i])fix(nxt[i],-1); if(nxt[nxt[i]])fix(nxt[nxt[i]],1); } sort(q+1,q+m+1,cmp1); for(int i=1;i<=m;i++) { printf("%d\n",q[i].ans); } return 0; }