【分块】Gty的二逼妹子序列[LUOGU P4867] [莫队+分块]

题目:

题目链接:Gty的二逼妹子序列
题解:
什么**题目嘛,一点都没有意思,因为个数组大小卡了我将近四天,我查了好长时间才查出来,快气死了,,,(╯>д<)╯⁽˙³˙⁾
(下面才是正经的题解:)
题目中是让求l,r中的权值在(a,b)中的个数,所以就会想到用莫队进行对了l,r进行处理,然后在按套路开个桶,在对于(a,b)(就是对所有权值)进行分块写,(这里其实可以用离散化的,但是这个范围就不需要了吧),这样的就复杂度就降低了很多。
其中最重要的就是对于权值的分块。
(重要的还是数组大小啊,,,(坑死我了))

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
    return s*w; 
} 
const int sea=1000005;
const int pool=1005;
struct hit{int l,r,id,x,y;}q[sea];
int n,m,block,num,belong[sea],a[sea],ans[sea],l[pool],r[pool],lazy[pool],f[sea];
bool cmp(hit a,hit b){if(belong[a.l]==belong[b.l]) return a.r<b.r;return a.l<b.l;}
int fk(int x,int y)//权值分块
{
    int tmp=0;
    for(int i=belong[x]+1;i<belong[y];i++) tmp+=lazy[i]; 
    if(belong[x]==belong[y])
    for(int i=x;i<=y;i++) {if(f[i]) tmp++;}
    else
    {
        for(int i=x;i<=r[belong[x]];i++) if(f[i]) tmp++;
        for(int i=l[belong[y]];i<=y;i++) if(f[i]) tmp++;
    }
    return tmp;
}
void add(int x){f[x]++; if(f[x]==1) lazy[belong[x]]++;}
void del(int x){f[x]--; if(f[x]==0) lazy[belong[x]]--;}
int main()
{
    n=read(); m=read(); block=sqrt(n/2);
    for(int i=1;i<=n;i++) belong[i]=(i-1)/block+1;
    num=n/block; if(num%block) num++;
    for(int i=1;i<=num;i++) r[i]=i*block,l[i]=(i-1)*block+1;
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].x=read(),q[i].y=read(),q[i].id=i;
    sort(q+1,q+m+1,cmp);
    int L=1,R=0;
    for(int i=1;i<=m;i++)
    {
        while(L<q[i].l) del(a[L]),L++;
        while(L>q[i].l) L--,add(a[L]);
        while(R<q[i].r) R++,add(a[R]);
        while(R>q[i].r) del(a[R]),R--;
        ans[q[i].id]=fk(q[i].x,q[i].y);
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
} 

谋事在人,成事在天,做好自己,剩下的,就交给Jesus就好了。 ——Blng

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值