P4688 Ynoi2016 掉进兔子洞

P4688 Ynoi2016 掉进兔子洞

经典莫队加 bitset

思路

不难发现最终答案就是:

(r1l1+1)+(r2l2+1)+(r3l3+1)3×size

其中 size 表示 3 个区间内出现了多少个公共元素。

看到这么多区间,不妨有把区间拆下来搞莫队的想法。

先不考虑询问个数的限制,我们考虑使用 bitset 维护出现多少个公共元素。

然而 bitset 维护出来的是多少种而不是个数。

又然而我们可以先将序列离散化,离散化时每个元素的新值赋为小于等于它的元素的个数。

在莫队加入一个节点时,把 bitset 中的第 pcntp 位标为 1

cntp 为当前区间内 p 元素的个数。

然后你就会发现,bitset 中不同的值的元素所储存位置是不同的(这个显而易见)。

然后你又发现,bitset 中不同区域的 1 的个数代表了某些值相等的元素的个数。

接着你把 3 个区间分别的 bitset 求交,统计 1 的个数,就求出了 size

然而一次性不可以处理这么多的区间,我们把询问分组处理即可。

时间复杂度 n2nw,然而卡不到莫队上限。

CODE

#include<bits/stdc++.h>
using namespace std;

#define M 2e4

const int maxn=1e5+5,maxm=2e4+5;

struct qry
{
    int l,r,t;
}q[maxm*3];

int n,m,tot=1;
int a[maxn],cnt[maxn],nans[maxm];

bitset<maxn>ans[maxm],nb;

map<int,int>mp;

inline bool cmp1(qry a,qry b){return a.l<b.l;}
inline bool cmp2(qry a,qry b){return a.r<b.r;}
inline void ins(int a){nb[a-cnt[a]]=1;cnt[a]++;}
inline void del(int a){cnt[a]--;nb[a-cnt[a]]=0;}
inline void solve()
{
    if(tot>=m) return ;
    int tp=0;
    for(int i=1;i<=M&&tot<=m;i++,tot++)
    {
        ++tp;scanf("%d%d",&q[tp].l,&q[tp].r);q[tp].t=i;nans[i]+=q[tp].r-q[tp].l+1;
        ++tp;scanf("%d%d",&q[tp].l,&q[tp].r);q[tp].t=i;nans[i]+=q[tp].r-q[tp].l+1;
        ++tp;scanf("%d%d",&q[tp].l,&q[tp].r);q[tp].t=i;nans[i]+=q[tp].r-q[tp].l+1;
    }
    for(int i=1;i<=tp/3;i++) ans[i].set();
    sort(q+1,q+tp+1,cmp1);
    for(int i=1;i<=tp;i+=320)
    {
        int r=min(i+319,tp);
        sort(q+i,q+r+1,cmp2);
    }
    int nl=0,nr=0;
    for(int i=1;i<=tp;i++)
    {
        if(nr<q[i].l)
        {
            for(int j=nl;j<=nr;j++) del(a[j]);
            nl=q[i].l,nr=q[i].r;
            for(int j=nl;j<=nr;j++) ins(a[j]);
        }
        else
        {
            while(nl<q[i].l) del(a[nl]),nl++;
            while(nl>q[i].l) nl--,ins(a[nl]);
            while(nr<q[i].r) nr++,ins(a[nr]);
            while(nr>q[i].r) del(a[nr]),nr--;
        }
        ans[q[i].t]&=nb;
    }
    for(int i=nl;i<=nr;i++) del(a[i]);
    for(int i=1;i<=tp/3;i++) printf("%lld\n",nans[i]-ans[i].count()*3);
    for(int i=1;i<=tp/3;i++) nans[i]=0;tp=0;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),mp[a[i]]++;
    map<int,int>::iterator it2,it1;
    for(it1=mp.begin(),it2=it1,it2++;it2!=mp.end();it1++,it2++) it2->second+=it1->second;
    for(int i=1;i<=n;i++) a[i]=mp[a[i]];
    for(int i=1;i<=5;i++) solve();
}
posted @   彬彬冰激凌  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示