[BZOJ3236][Ahoi2013]作业(莫队+分块)

题目描述

传送门

题解

和Gty的二逼妹子序列那道题是一样的,只不过多加了一问而已
对权值分块,然后将区间离线之后莫队,每一次修改 O(1) ,查询 O(n)

代码

#include
#include
#include
#include
#include
using namespace std;
#define N 1000005

int n,m,block,t,ansum,ansval,ans[N][2];
int a[N],num[N],L[N],R[N],cnt[N],sum[N],val[N];
struct data{int l,r,x,y,id;}q[N];

int cmp(data a,data b)
{
    return num[a.l]int l,int r,int f)
{
    for (int i=l;i<=r;++i)
    {
        int last=cnt[a[i]];
        sum[num[a[i]]]-=cnt[a[i]];
        cnt[a[i]]+=f;
        sum[num[a[i]]]+=cnt[a[i]];
        if (!last&&cnt[a[i]]) ++val[num[a[i]]];
        else if (last&&!cnt[a[i]]) --val[num[a[i]]];
    }
}
void query(int l,int r)
{
    ansum=0,ansval=0;
    if (num[l]==num[r])
    {
        for (int i=l;i<=r;++i)
            if (cnt[i]) ansum+=cnt[i],++ansval;
        return;
    }
    if (l==L[num[l]]) l=num[l];
    else
    {
        for (int i=l;i<=R[num[l]];++i)
            if (cnt[i]) ansum+=cnt[i],++ansval;
        l=num[l]+1;
    }
    if (r==R[num[r]]) r=num[r];
    else
    {
        for (int i=L[num[r]];i<=r;++i)
            if (cnt[i]) ansum+=cnt[i],++ansval;
        r=num[r]-1;
    }
    for (int i=l;i<=r;++i) ansum+=sum[i],ansval+=val[i];
}
int main()
{
    scanf("%d%d",&n,&m);
    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].x,&q[i].y);
        q[i].x=max(q[i].x,1);q[i].y=min(q[i].y,n);
        q[i].id=i;
    }
    block=sqrt(n);t=(n-1)/block+1;
    for (int i=1;i<=n;++i) num[i]=(i-1)/block+1;
    L[1]=1,R[1]=block;
    for (int i=2;i<=n;++i) L[i]=L[i-1]+block,R[i]=R[i-1]+block;R[t]=n;
    sort(q+1,q+m+1,cmp);
    modui(q[1].l,q[1].r,1);
    query(q[1].x,q[1].y);
    ans[q[1].id][0]=ansum,ans[q[1].id][1]=ansval;
    for (int i=2;i<=m;++i)
    {
        if (q[i-1].l<q[i].l) modui(q[i-1].l,q[i].l-1,-1);
        else modui(q[i].l,q[i-1].l-1,1);
        if (q[i-1].r<q[i].r) modui(q[i-1].r+1,q[i].r,1);
        else modui(q[i].r+1,q[i-1].r,-1);
        query(q[i].x,q[i].y);
        ans[q[i].id][0]=ansum,ans[q[i].id][1]=ansval;
    }
    for (int i=1;i<=m;++i) printf("%d %d\n",ans[i][0],ans[i][1]);
}

你可能感兴趣的:(题解,莫队,分块)