P1972 HH的项链
前提:这不是一份完整的题解,仅仅是按照莫队的模板的板子来打的
- 思路已经非常明确了,按照莫队的方法逐步加入和离开当前区间,知道这个区间符合询问区间
- 接下来要对其中一个优化操作进行阐述:
-
for(int i=1;i<=m;i++) { while(l<q[i].l) now-=!--cnt[a[l++]]; while(l>q[i].l) now+=!cnt[a[--l]]++; while(r<q[i].r) now+=!cnt[a[++r]]++; while(r>q[i].r) now-=!--cnt[a[r--]]; ans[q[i].id]=now; } 这一个其实上和 void add(int pos) { if(!cnt[aa[pos]]) ++now; ++cnt[aa[pos]]; } void del(int pos) { --cnt[aa[pos]]; if(!cnt[aa[pos]]) --now; } 和这个: while(l < ql) del(l++); while(l > ql) add(--l); while(r < qr) add(++r); while(r > qr) del(r--); 是相同的
- 首先要注意一点,某个点l或者r说明[l,r]区间数据已经全部统计(包括l和r点),所以说这也是为甚么l=1,r=0;
-
我们来看,以左端点为例,因为l是要删除,所以是l++(删除当前,--cnt是为了判断当前的cnt[l]是否为0,所以是这样的顺序)
- 2.同理:因为l已经加入,所以是--l<同时因为要判断先前是否为0,所以是cnt++;
- 3.对于r来说也是一样,向右,扩展,先加入所以++r,先判断所以cnt++
- 4.向左,减少,后减少所以r--,后判断所以是--cnt;
- 注意一下bnum的计算以及奇偶性优化就可以了
代码如下:
#include <stdio.h> #include <algorithm> #include <cstring> #include <cmath> #include <cctype> using namespace std; const int maxn=30010; const int maxm=1000020; struct Ques { int l,r,id; }q[maxm]; int ans[maxm],belong[maxm],a[maxm],cnt[maxm]; int bnum,size; int n,m; int bmp(Ques x,Ques y)//×¢ÒâÕâÀï±àдµÄÊǽṹÌ壬Ҫ°´ÕսṹÌåÀ´ { return (belong[x.l]^belong[y.l])?belong[x.l]<belong[y.l]:(belong[x.l]&1)?x.r<y.r:x.r>y.r; } int read() { int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=(x<<1)+(x<<3)+c-'0',c=getchar(); return x; } void print(int x) { if(x/10) print(x/10); putchar(x%10+'0'); } int main() { n=read(); size=sqrt(n); bnum=ceil((double)n/size);// for(int i=1;i<=bnum;i++) for(int j=(i-1)*size+1;j<=i*size;j++) belong[j]=i; for(int i=1;i<=n;i++) a[i]=read(); m=read(); for(int i=1;i<=m;i++) { q[i].l=read();q[i].r=read(); q[i].id=i; } sort(q+1,q+1+m,bmp); int l=1,r=0,now=0;//l=1£¬r=0 for(int i=1;i<=m;i++) { while(l<q[i].l) now-=!--cnt[a[l++]]; while(l>q[i].l) now+=!cnt[a[--l]]++; while(r<q[i].r) now+=!cnt[a[++r]]++; while(r>q[i].r) now-=!--cnt[a[r--]]; ans[q[i].id]=now; } for(int i=1;i<=m;i++) print(ans[i]),putchar('\n'); return 0; }
浙公网安备 33010602011771号