BZOJ 3236: [Ahoi2013]作业【莫队+树状数组】

3236: [Ahoi2013]作业

【题目描述】
传送门

【题解】

莫队+树状数组,树状数组维护前缀和,这个做法有点笨,87秒勉强卡过。

代码如下

#include<cmath>
#include<cstdio>
#include<cctype>
#include<algorithm>
#define MAXN 100005
#define MAXE 1000005
using namespace std;
int n,m,K,tot,a[MAXN],f[2][MAXN],hsh[MAXN];
struct xcw{
    int L,R,A,B,id;
    bool operator <(const xcw b)const{return (L/K<b.L/K)||(L/K==b.L/K)&&(R<b.R);}
}Q[MAXE];
struct Answer{int F,S;}Ans[MAXE];
int read(){
    int ret=0;char ch=getchar();bool f=1;
    for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
    for(; isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-48;
    return f?ret:-ret;
}
void put(int Now,int x,int p){for(;x<=tot;x+=x&-x) f[Now][x]+=p;}
int get(int Now,int x){
    int Sum=0;
    for(;x;x-=x&-x) Sum+=f[Now][x];
    return Sum;
}
void Del(int x){
    hsh[a[x]]--;put(0,a[x],-1);
    if(!hsh[a[x]]) put(1,a[x],-1);
}
void Add(int x){
    if(!hsh[a[x]]) put(1,a[x],1);
    hsh[a[x]]++;put(0,a[x],1);
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("prob.in","r",stdin);
    freopen("prob.out","w",stdout);
    #endif
    n=read(),m=read();K=sqrt(n);
    for(int i=1;i<=n;i++) tot=max(tot,a[i]=read());
    for(int i=1,tt;i<=m;i++) Q[i]=(xcw){read(),read(),read(),0,i},tt=read(),tot=max(tot,tt),Q[i].B=tt;
    sort(Q+1,Q+1+m);
    int L=1,R=0;
    for(int i=1;i<=m;i++){
        while(L<Q[i].L) Del(L++);
        while(L>Q[i].L) Add(--L);
        while(R<Q[i].R) Add(++R);
        while(R>Q[i].R) Del(R--);
        Ans[Q[i].id]=(Answer){get(0,Q[i].B)-get(0,Q[i].A-1),get(1,Q[i].B)-get(1,Q[i].A-1)};
    }
    for(int i=1;i<=m;i++) printf("%d %d\n",Ans[i].F,Ans[i].S);
    return 0;
}
posted @ 2018-06-16 22:25  XSamsara  阅读(128)  评论(0编辑  收藏  举报