[BZOJ3809]Gty的二逼妹子序列(莫队+分块)

来源:互联网 发布:mp3声音放大软件 编辑:程序博客网 时间:2024/04/29 10:33

题目描述

传送门

题解

莫队+树状数组的思路很显然,但是时间O(mnlog2n)
莫队+权值分块的做法比较优越。将权值分块之后修改可以做到O(1)查询O(n)

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;const int max_n=1e5+5;const int max_m=1e6+5;const int max_sqrt=350;int n,m,t,num,ans;int a[max_n],val[max_n],sum[max_sqrt];struct hp{int l,r,a,b,id,final;}q[max_m];inline int cmp(hp a,hp b){    int num1,num2;    if (a.l%t==0) num1=a.l/t; else num1=a.l/t+1;    if (b.l%t==0) num2=b.l/t; else num2=b.l/t+1;    return num1<num2||(num1==num2&&a.r<b.r);}inline int ask(int l,int r){    int ans=0,k,lrange,rrange,numl,numr;    if (l%t==0) numl=l/t;    else numl=l/t+1;    if (r%t==0) numr=r/t;    else numr=r/t+1;    if (numl==numr){        for (int i=l;i<=r;++i)          if (val[i]) ans++;        return ans;    }    lrange=numl+1;    k=numl*t;    for (int i=l;i<=k;++i)      if (val[i]) ans++;    k=(numr-1)*t+1;    for (int i=k;i<=r;++i)      if (val[i]) ans++;    rrange=numr-1;    for (int i=lrange;i<=rrange;++i)      ans+=sum[i];    return ans;}int main(){    scanf("%d%d",&n,&m);    t=(int)sqrt(n);    for (int i=1;i<=n;++i) scanf("%d",&a[i]);    for (int i=1;i<=m;++i) scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].a,&q[i].b),q[i].id=i;    sort(q+1,q+m+1,cmp);    for (int i=q[1].l;i<=q[1].r;++i){        if (a[i]%t==0) num=a[i]/t; else num=a[i]/t+1;        ++val[a[i]];        if (val[a[i]]==1) ++sum[num];    }    ans=ask(q[1].a,q[1].b);    q[q[1].id].final=ans;    for (int i=2;i<=m;++i){        if (q[i-1].l<q[i].l)          for (int j=q[i-1].l;j<q[i].l;++j){            if (a[j]%t==0) num=a[j]/t; else num=a[j]/t+1;            --val[a[j]];            if (!val[a[j]]) --sum[num];          }        if (q[i-1].l>q[i].l)          for (int j=q[i-1].l-1;j>=q[i].l;--j){            if (a[j]%t==0) num=a[j]/t; else num=a[j]/t+1;            ++val[a[j]];            if (val[a[j]]==1) ++sum[num];          }        if (q[i-1].r<q[i].r)          for (int j=q[i-1].r+1;j<=q[i].r;++j){            if (a[j]%t==0) num=a[j]/t; else num=a[j]/t+1;            ++val[a[j]];            if (val[a[j]]==1) ++sum[num];          }        if (q[i-1].r>q[i].r)          for (int j=q[i-1].r;j>q[i].r;--j){            if (a[j]%t==0) num=a[j]/t; else num=a[j]/t+1;            --val[a[j]];            if (!val[a[j]]) --sum[num];          }        ans=ask(q[i].a,q[i].b);        q[q[i].id].final=ans;    }    for (int i=1;i<=m;++i)      printf("%d\n",q[i].final);}
0 0
原创粉丝点击