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;
    
}
View Code

 

posted @ 2020-09-01 13:31  ILH  阅读(134)  评论(0)    收藏  举报