分块_莫队算法

题意:
给定N个数,记为ai(1<=i<= N),求区间内某两个数和为给定的M的对数。一共Q次询问
数据范围:
T<=20
N<= 20000,M <= 20000
1 <= ai<M
Q<= 20000,1<= l < r <= n
现在知道[l,r]的答案ans,可以O(1)得出[l,r+1]的答案
c[i]表示现在值为i的数有几个,那么a[r+1]=x对答案贡献了c[M-x],所以[l,r+1]的答案就是ans+c[M-x]
同理可以O(1)得到[l-1,r]的答案
voidinsert(int x){
    x=a[x];
    ans+=c[M-x];
    ++c[x];
}
现在知道[l,r]的答案ans,可以O(1)得出[l,r-1]的答案
假设a[r]=x,要分两种情况讨论:
1)x+x!=M, 答案是 ans-c[M-x]
2)x+x==M,答案是ans-(c[M-x]-1)
同理可以O(1)得到[l+1,r]的答案
void erase(int x){
    x=a[x];
    ans-=c[M-x]-(x+x==M);
    --c[x];
}
现在知道[p,q]的答案,现在求[l,r]的答案


考虑右端点:
1)如果q<r,把a[q+1],a[q+2]…a[r]插入
2)如果q>r,把a[r+1],a[r+2]…a[q]删除
时间复杂度是|q-r|

考虑左端点:
1)如果p<l,把a[p],a[p+1]…a[l]删除
2)如果p>l,把a[l+1],a[l+2]…a[p]插入
时间复杂度是|p-l|

这个过程时间复杂度就是|p-l|+|q-r|

while (q<r) insert(++q);
while (q>r) erase(q--);
while (p<l) erase(p++);
while (p>l) insert(--p);
1)读入所有的询问,并记下是第几个询问
2)把N个数分成sqrt(N)块,算出每个询问的左端点在哪个块 pos=l/sqrt(N)
3)把询问以pos为第一关键字,r为第二关键字排序
4)按新的顺序求出所有询问的答案
struct Query{
    int id,l,r,pos;
    bool operator<(const Query &t)const{
        return pos!=t.pos?pos<t.pos:r<t.r; 
    }
};
Query b[21000];
sort(b+1,b+Q+1);  //  把b[1],b[2]...b[Q]排序
int main(){
    int _;
    scanf("%d",&_);
    while (_--){
        scanf("%d%d",&N,&M);
        int i;
        for (i=1;i<=N;i++) scanf("%d",&a[i]);
        scanf("%d",&Q);
        for (i=1;i<=Q;i++){
            b[i].id=i;
            scanf("%d%d",&b[i].l,&b[i].r);
            b[i].pos=b[i].l/sqrt(N);
        }
        sort(b+1,b+Q+1);
        memset(c,0,sizeof(c));
        ans=0;
        int p=1,q=1; insert(1);
        for (i=1;i<=Q;i++){
            int l=b[i].l,r=b[i].r;
            while (q<r) insert(++q);
            while (q>r) erase(q--);
            while (p<l) erase(p++);
            while (p>l) insert(--p);
            t[b[i].id]=ans;
        }
        for (i=1;i<=Q;i++) printf("%I64d\n",t[i]);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值