[bzoj1878][SDOI2009]HH的项链_莫队
HH 的项链 bzoj-1878 SDOI-2009
题目大意:给定一个n个数的序列。m次询问,每次询问一段区间内数的种类数。
注释:$1\le n\le 5\cdot 10^4$,$1\le m\le 2\cdot 10^5$。
想法:莫队裸题。
左端点按照块编号排序,右端点按照时间戳排序。
然后每次左右指针动的时候记录桶是不是从0变成1或者从1变成0,记得更新答案。
即当前区间的答案就是莫队上的区间的答案。
最后,附上丑陋的代码... ...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define N 50010 #define M 200010 #define V 1000010 using namespace std; int a[N],blg[N],stack[V],ans[M]; int now; inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;} int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;} struct Query { int l,r,id; }q[M]; inline bool cmp(const Query &x,const Query &y) {return blg[x.l]==blg[y.l]?x.r<y.r:blg[x.l]<blg[y.l];} inline void add(int x) {if(!stack[x]) now++; stack[x]++;} inline void del(int x) {if(stack[x]==1) now--; stack[x]--;} int main() { int n=rd(); int unit=sqrt(n); int t=n/unit; for(int i=1;i<=t;i++) { for(int j=(i-1)*unit+1;j<=i*unit;j++) { blg[j]=i; a[j]=rd(); } } if(unit*t<n) { t++; for(int i=unit*(t-1)+1;i<=n;i++) { blg[i]=t; a[i]=rd(); } } int m=rd(); for(int i=1;i<=m;i++) { q[i].l=rd(),q[i].r=rd(); q[i].id=i; } sort(q+1,q+m+1,cmp); int l=0,r=0; for(int i=1;i<=m;i++) { while(l<q[i].l) del(a[l]),l++; while(l>q[i].l) l--,add(a[l]); while(r<q[i].r) r++,add(a[r]); while(r>q[i].r) del(a[r]),r--; ans[q[i].id]=now; } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
小结:莫队...
| 欢迎来原网站坐坐! >原文链接<