您的位置:首页 > 其它

询问任意区间的min,max,gcd,lcm,sum,xor,or,and

2015-09-24 20:09 483 查看
给我们n个数,然后有m个询问,每个询问为L,R,询问区间[L,R]的最大最小值,最小公约数,最大公约数,和,异或,或,且

这些问题通通可以用RMQ的思想来解决。

以下用xor来作为例子

设dp[i][j]为以i开头的,长度为2^j的区间的所有值得异或

那么dp[i][j] = dp[i][j-1] xor dp[i+(1<<(j-1))][j-1]

这样,运用动态规划的思想,我们可以在nlogn的时间复杂度内算出以任意点开头的,长度为1,2,4,8...2^j 的区间的异或值。

那么询问任意区间的异或值时,只要将L->R之间的距离用二进制数来表示,那么只需要log(R-L+1)步就能求出所需的询问。

#include <stdio.h>
#include <string.h>
const int N = 100000 + 10;
int a
;
int dp
[30];
int n;
void init()
{
for(int i=1;i<=n;++i)
dp[i][0] = a[i];
for(int j=1;(1<<j)<=n;++j)
{
for(int i=1;i+(1<<j)-1<=n;++i)
{
dp[i][j] = dp[i][j-1] ^ dp[i+(1<<(j-1))][j-1];
}
}
}

int query(int L, int R)
{
int ans = 0;
int seg = R - L + 1;
int tmp = 1, i = 0;
while(seg)
{
if(seg&1)
{
ans ^= dp[L][i];
L += tmp;
}
seg>>=1;
i++;
tmp = tmp * 2;
}
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
init();
int m,L,R;
scanf("%d",&m);
while(m--)
{
scanf("%d%d",&L,&R);
printf("%d\n",query(L,R));
}
}
return 0;
}


View Code

同理,以上所说的其他问题同样能够求解。

预处理的时间复杂度是O(nlogn), 每次询问是O(logn)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: