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

给我们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)步就能求出所需的询问。

 1 #include <stdio.h>
 2 #include <string.h>
 3 const int N = 100000 + 10;
 4 int a[N];
 5 int dp[N][30];
 6 int n;
 7 void init()
 8 {
 9     for(int i=1;i<=n;++i)
10         dp[i][0] = a[i];
11     for(int j=1;(1<<j)<=n;++j)
12     {
13         for(int i=1;i+(1<<j)-1<=n;++i)
14         {
15             dp[i][j] = dp[i][j-1] ^ dp[i+(1<<(j-1))][j-1];
16         }
17     }
18 }
19 
20 int query(int L, int R)
21 {
22     int ans = 0;
23     int seg = R - L + 1;
24     int tmp = 1, i = 0;
25     while(seg)
26     {
27         if(seg&1)
28         {
29             ans ^= dp[L][i];
30             L += tmp;
31         }
32         seg>>=1;
33         i++;
34         tmp = tmp * 2;
35     }
36     return ans;
37 }
38 int main()
39 {
40     while(scanf("%d",&n)!=EOF)
41     {
42         for(int i=1;i<=n;++i)
43             scanf("%d",&a[i]);
44         init();
45         int m,L,R;
46         scanf("%d",&m);
47         while(m--)
48         {
49             scanf("%d%d",&L,&R);
50             printf("%d
",query(L,R));
51         }
52     }
53     return 0;
54 }
View Code

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

预处理的时间复杂度是O(nlogn), 每次询问是O(logn)

原文地址:https://www.cnblogs.com/justPassBy/p/4836397.html