BZOJ 3809: Gty的二逼妹子序列(莫队+分块)

6 篇文章 0 订阅
4 篇文章 0 订阅

题目

Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题。
对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数。
为了方便,我们规定妹子们的美丽度全都在[1,n]中。
给定一个长度为n(1<=n<=100000)的正整数序列s(1<=si<=n),对于m(1<=m<=1000000)次询问“l,r,a,b”,每次输出sl…sr中,权值∈[a,b]的权值的种类数。

分析

要么写树套树,可是只有28M的空间,所以莫队吧。
莫队+树状数组很好想,但是这样就是O(n^1.5logn)。
有个很厉害的思路就是用分块把修改变成O(1),查询变成O(n^0.5)
这样最终时间复杂度就是O(n*1.5)
卡一卡就能过去

这里的优化思路可以这么分析:
用树状数组则修改O(n*n^0.5*logn),查询O(n*(n^0.5+logn)),所以想个办法再综合一下,分块刚刚好嘛

orzPoPoQQQ大爷的加速输入

顺便,由于分块没有初始化,然后TLE了3次,每次卡80S,卡住了不少人,对不起大家QAQ。

代码

注意:
1、分块的初始化操作即使不做也不会错,但是会T很惨
2、莫队注意修改的时候++i和i++不同情况不一样。

#include<cmath>
#include<queue>
#include<cctype>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e5+105,maxm=1e6+105;
namespace IStream{  
    const int L=1<<15;  
    char buffer[L],*S,*T;  
    inline char Get_Char()  
    {  
        if(S==T)  
        {  
            T=(S=buffer)+fread(buffer,1,L,stdin);  
            if(S==T) return EOF;  
        }  
        return *S++;  
    }  
    inline void Rd(int &re) 
    {  
        char c; 
        re=0;
        for(c=Get_Char();(c<'0'||c>'9');c=Get_Char());  
        while(c>='0'&&c<='9')  
            re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();  
    } 
    int tt[20],sz;
    inline void Pt(int x)
    {
        sz=0;
        do{
            tt[++sz]=x%10;
            x/=10;
        }while(x);
        for(int i=sz;i;i--)putchar(tt[i]^48);
        putchar('\n');
    }
}
int n,m;
int co[maxn],belong[maxn];
struct block{
    static const int TIM=320;
    int num,vis[maxn],d[maxn/TIM+5],L[maxn/TIM+5],R[maxn/TIM+5];
    void Build()
    {
        L[0]=R[0]=0;
        for(num=1;num*TIM<n;num++)
        {
            L[num]=R[num-1]+1,R[num]=L[num]+TIM-1;
            for(int i=L[num];i<=R[num];i++)belong[i]=num;
        }
        L[num]=R[num-1]+1,R[num]=n;
        for(int i=L[num];i<=R[num];i++)belong[i]=num;
    } 
    void add(int v)
    {
        if(!vis[v])d[belong[v]]++;
        vis[v]++;
    }
    void del(int v)
    {
        if(vis[v]==1)d[belong[v]]--;
        vis[v]--;
    }
    int query(int l,int r)
    {
        int ret=0;
        if(belong[l]==belong[r])
        {
            for(int i=l;i<=r;i++)if(vis[i])ret++;
            return ret;
        }
        for(int i=l;i<=R[belong[l]];i++)if(vis[i])ret++;
        for(int i=belong[l]+1;R[i]<r;i++)ret+=d[i];
        for(int i=L[belong[r]];i<=r;i++)if(vis[i])ret++;
        return ret;
    }
}blo;
namespace modui
{
    int ans[maxm];
    struct data{
        int l,r,a,b,id;
        friend bool operator<(data a,data b)
        {
            return belong[a.l]!=belong[b.l]?belong[a.l]<belong[b.l]:a.r<b.r;
        }
    }q[maxm];
    void Init()
    {
        IStream::Rd(n);IStream::Rd(m);
        blo.Build();
        for(int i=1;i<=n;i++)IStream::Rd(co[i]);
        for(int i=1;i<=m;i++)
        {
            q[i].id=i;
            IStream::Rd(q[i].l);
            IStream::Rd(q[i].r);
            IStream::Rd(q[i].a);
            IStream::Rd(q[i].b);
        }
        sort(q+1,q+m+1);
    }   
    void modui()
    {
        int L=1,R=0;
        for(int i=1;i<=m;i++)
        {
            while(L<q[i].l)blo.del(co[L++]);
            while(L>q[i].l)blo.add(co[--L]);
            while(R<q[i].r)blo.add(co[++R]);
            while(R>q[i].r)blo.del(co[R--]);
            ans[q[i].id]=blo.query(q[i].a,q[i].b);
        }
    }
    void work()
    {
        Init();
        modui();
        for(int i=1;i<=m;i++)
            IStream::Pt(ans[i]);
    }
}
int main()
{
    modui::work();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值