[莫队]luogu3674 小清新人渣的本愿

本文介绍一种使用莫队算法结合bitset解决区间查询问题的方法,特别是针对区间内是否存在两数之差、和或乘积等于特定值的操作,通过代码实现展示了如何优化以满足严格的时间限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1,2,3

题解

这题用莫队和bitset和卡常
莫队的时间O(nn)
bitset时间除以64
总时间O(玄学???)
所以要卡常

1.读入优化
2.函数都要加inline(效果明显)
3.printf()用puts()代替
4.bitset.count()用bitset.any()代替(效果明显)

n=10^5时可以跑进1s

ac代码

#include<cstdio>
#include<algorithm>
#include<bitset>
#define N 100010
#define MX 100000
#define B 320
using namespace std;
inline int rd(){
    char c;
    int x=0,y=1;
    while((c=getchar())<'0'||c>'9')if(c=='-')y=-1;
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    return x*y;
}
struct Que{
    int o,p,q,v,id;
}c[N];
bitset<N>f,g;
int b[N],v[N],n,m,ans[N],a[N],l,r;
inline bool cmp(Que p,Que q){
    if(b[p.p]==b[q.p])return p.q<q.q;
    return b[p.p]<b[q.p];
}
inline void Insert(int x){
    if(++v[a[x]]==1){
        f.set(a[x]);
        g.set(MX-a[x]);
    }
}
inline void Delete(int x){
    if(--v[a[x]]==0){
        f.reset(a[x]);
        g.reset(MX-a[x]);
    }
}
inline bool Solve(int o,int x){
    if(o==1)return (f&(f<<x)).any();
    if(o==2)return (g&(f<<(MX-x))).any();
    for(int i=1;i<=B;i++)if(x%i==0&&v[i]&&v[x/i])return 1;
    return 0;
}
int main(){
    freopen("data.txt","r",stdin);
    n=rd(),m=rd();
    for(int i=1;i<=n;i++)a[i]=rd();
    for(int i=1;i<=n;i++)b[i]=(i-1)/B+1;
    for(int i=1;i<=m;i++){
        c[i].o=rd(),c[i].p=rd(),c[i].q=rd(),c[i].v=rd();
        c[i].id=i;
    }
    sort(c+1,c+m+1,cmp);
    l=c[1].p; r=c[1].p-1; 
    for(int i=1;i<=m;i++){
        while(l<c[i].p)Delete(l++);
        while(l>c[i].p)Insert(--l);
        while(r<c[i].q)Insert(++r);
        while(r>c[i].q)Delete(r--);
        ans[c[i].id]=Solve(c[i].o,c[i].v);
    }
    for(int i=1;i<=m;i++)if(ans[i])puts("hana");
    else puts("bi");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值