分块_莫队算法
2014-05-08 23:59
176 查看
题意:
给定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]);
}
}
给定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]);
}
}
相关文章推荐
- 【莫队算法】【权值分块】bzoj3236 [Ahoi2013]作业
- hiho 1553区间统计 莫队算法+分块思想
- bzoj 3585 mex - 线段树 - 分块 - 莫队算法
- bzoj 3809: Gty的二逼妹子序列(莫队算法+分块)
- 【BZOJ2038】小Z的袜子(hose)(莫队算法 + 分块)
- WHU-1551-Pairs(莫队算法+分块实现)
- 莫队算法(最小曼哈顿生成树或者分块处理)
- NBUT 1457 Sona 莫队算法 分块处理
- 【BZOJ3809】Gty的二逼妹子序列【莫队算法】【分块】
- BZOJ 3809 Gty的二逼妹子序列 莫队算法+分块
- 【莫队算法】【权值分块】bzoj3339 Rmq Problem
- 【DFS序】【莫队算法】【权值分块】bzoj1803 Spoj1487 Query on a tree III
- hdu 4638 Group(莫队算法+分块)
- 【BZOJ-3809】Gty的二逼妹子序列 分块 + 莫队算法
- 【莫队算法】【权值分块】bzoj2223 [Coci 2009]PATULJCI
- 【莫队算法】【权值分块】poj2104 K-th Number / poj2761 Feed the dogs
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose)|分块|莫队算法
- 【莫队算法】【权值分块】bzoj3809 Gty的二逼妹子序列
- BZOJ 3809 Gty的二逼妹子序列 莫队算法+分块
- 【BZOJ3809/3236】Gty的二逼妹子序列 [Ahoi2013]作业 莫队算法+分块