[BZOJ 3236][Ahoi2013]作业(莫队+树状数组)

Description

传送门

Solution

莫队

一开始维护数的个数和数值的个数都用了树状数组,果断超时QAQ

把数的个数改成了按权值分块

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define N 100005
#define M 1000005
using namespace std;
int n,m,block,x[N],pos[N],ans1[M],ans2[M],num[N];
int g1[N];
struct Node
{
    int l,r,a,b,id;
    bool operator < (const Node& t) const
    {
        if(pos[l]==pos[t.l])
        return pos[r]<pos[t.r];
        else return pos[l]<pos[t.l];
    }
}q[M];
struct BIT
{
    int c[N];
    inline int lowbit(int x){return x&-x;}
    void add(int pos,int x)
    {
        while(pos<=n)
        c[pos]+=x,pos+=lowbit(pos);
    }
    int query(int pos)
    {
        int res=0;
        while(pos>0)res+=c[pos],pos-=lowbit(pos);
        return res;
    }
}t2;
int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
void change(int t,int f)
{
    g1[pos[x[t]]]+=f;//t1.add(x[t],f);
    if(num[x[t]]==0&&f==1)t2.add(x[t],1);
    else if(num[x[t]]==1&&f==-1)t2.add(x[t],-1);
    num[x[t]]+=f;
}
void query(int id,int a,int b)
{
    if(pos[a]==pos[b])
    {
        for(int i=a;i<=b;i++)
        ans1[id]+=num[i];
        return;
    }
    for(int i=a;i<=pos[a]*block;i++)ans1[id]+=num[i];
    for(int i=pos[a]+1;i<=pos[b]-1;i++)ans1[id]+=g1[i];
    for(int i=b;i>(pos[b]-1)*block;i--)ans1[id]+=num[i];
}
int main()
{
    n=read(),m=read();
    block=(int)sqrt(n);
    for(int i=1;i<=n;i++)
    x[i]=read(),pos[i]=(i-1)/block+1;
    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;
    sort(q+1,q+1+m);
    int l=1,r=0;
    for(int i=1;i<=m;i++)
    {
        while(l<q[i].l)change(l++,-1);
        while(l>q[i].l)change(--l,1);
        while(r>q[i].r)change(r--,-1);
        while(r<q[i].r)change(++r,1);
        if(q[i].a<0)q[i].a=1;
        query(q[i].id,q[i].a,q[i].b);
        ans2[q[i].id]=t2.query(q[i].b)-t2.query(q[i].a-1);
    }
    for(int i=1;i<=m;i++)
    printf("%d %d\n",ans1[i],ans2[i]);
    return 0;
}

 

posted @ 2017-06-09 08:10  Zars19  阅读(260)  评论(0编辑  收藏  举报