BZOJ 3236 作业

Posted on 2017-03-20 17:03  ziliuziliu  阅读(115)  评论(0编辑  收藏  举报

莫队+值域分块。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 100050
#define maxm 1000050
using namespace std;
int n,m,a[maxn],ans[maxm][3],pos[maxn],ret=316,st[maxn],tot=0;
int cnt[maxn][5];
struct query
{
    int l,r,a,b,id;
}q[maxm];
bool cmp(const query &x,const query &y)
{
    if (pos[x.l]!=pos[y.l]) return pos[x.l]<pos[y.l];
    else return x.r<y.r;
}
int read()
{
    char ch;int data=0;
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9')
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data;
}
void build()
{
    tot=1;
    for (int i=1;i<=n;i++)
    {
        pos[i]=tot;
        if (!(i%ret)) st[tot++]=i;
    }
    if (n%ret) st[tot]=n;else tot--;
}
void modify(int x,int val)
{
    int base=cnt[x][1];
    cnt[x][1]+=val;cnt[pos[x]][2]+=val;
    if ((cnt[x][1]==0) && (base==1)) {cnt[x][3]--;cnt[pos[x]][4]--;}
    if ((cnt[x][1]==1) && (base==0)) {cnt[x][3]++;cnt[pos[x]][4]++;}
}
void ask(int l,int r,int x)
{
    int ret1=0,ret2=0;
    if (pos[l]==pos[r])
    {
        for (int i=l;i<=r;i++)
            ret1+=cnt[i][1],ret2+=cnt[i][3];
    }
    else
    {
        for (int i=l;i<=st[pos[l]];i++) ret1+=cnt[i][1],ret2+=cnt[i][3];
        for (int i=st[pos[r]-1]+1;i<=r;i++) ret1+=cnt[i][1],ret2+=cnt[i][3];
        for (int i=pos[l]+1;i<=pos[r]-1;i++) ret1+=cnt[i][2],ret2+=cnt[i][4];
    }
    ans[q[x].id][1]=ret1;ans[q[x].id][2]=ret2;
}
int main()
{
    n=read();m=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<=m;i++)
    {
        q[i].l=read();q[i].r=read();q[i].a=read();q[i].b=read();
        q[i].id=i;
    }
    build();sort(q+1,q+m+1,cmp);
    int l=1,r=0;
    for (int i=1;i<=m;i++)
    {
        for (;r<q[i].r;r++) modify(a[r+1],1);
        for (;r>q[i].r;r--) modify(a[r],-1);
        for (;l<q[i].l;l++) modify(a[l],-1);
        for (;l>q[i].l;l--) modify(a[l-1],1);
        ask(q[i].a,q[i].b,i);
    }
    for (int i=1;i<=m;i++) printf("%d %d\n",ans[i][1],ans[i][2]);
    return 0;
}