二分+RMQ/双端队列/尺取法 HDOJ 5289 Assignment
1 /*
2 题意:问有几个区间最大值-最小值 < k
3 解法1:枚举左端点,二分右端点,用RMQ(或树状数组)求区间最值,O(nlog(n))复杂度
4 解法2:用单调队列维护最值,O(n)复杂度,用法
5 解法3:尺取法,用mutiset维护最值
6 */
7 #include <cstdio>
8 #include <algorithm>
9 #include <cstring>
10 #include <cmath>
11 using namespace std;
12
13 typedef long long ll;
14 const int MAXN = 1e5 + 10;
15 const int INF = 0x3f3f3f3f;
16 int a[MAXN];
17 int mn[MAXN][20], mx[MAXN][20]; //最多能保存524288的长度
18
19 int RMQ(int l, int r) {
20 int k = 0; while (1<<(k+1) <= r - l + 1) k++; //令k为满足1<<k <= r-l+1的最大整数
21 int MAX = max (mx[l][k], mx[r-(1<<k)+1][k]); //意思是区间最左边1<<k长度的最大值和最右边1<<k长度的最大值
22 int MIN = min (mn[l][k], mn[r-(1<<k)+1][k]); //可能有重叠的地方
23 return MAX - MIN;
24 }
25
26 int main(void) { //HDOJ 5289 Assignment
27 freopen ("B.in", "r", stdin);
28
29 int t; scanf ("%d", &t);
30 while (t--) {
31 int n, k; scanf ("%d%d", &n, &k);
32 for (int i=1; i<=n; ++i) {
33 scanf ("%d", &a[i]);
34 mn[i][0] = mx[i][0] = a[i];
35 }
36 for (int j=1; (1<<j)<=n; ++j) {
37 for (int i=1; i+(1<<j)-1<=n; ++i) {
38 mn[i][j] = min (mn[i][j-1], mn[i+(1<<(j-1))][j-1]); //mn[i][j]意思是从i开始,长度1<<j的区间的最小值
39 mx[i][j] = max (mx[i][j-1], mx[i+(1<<(j-1))][j-1]);
40 }
41 }
42
43 ll ans = 0;
44 for (int i=1; i<=n; ++i) {
45 int l = i, r = n;
46 while (l + 1 < r) { //二分使得l, r最远
47 int mid = (l + r) >> 1;
48 if (RMQ (i, mid) < k) l = mid;
49 else r = mid;
50 }
51 if (RMQ (i, r) < k) { //此时[l, r](l+1==r) 其中一个一定满足条件
52 ans += (r - i + 1);
53 }
54 else {
55 ans += (l - i + 1);
56 }
57 }
58 printf ("%I64d\n", ans);
59 }
60
61 return 0;
62 }
1 #include <cstdio>
2 #include <algorithm>
3 #include <cstring>
4 #include <cmath>
5 using namespace std;
6
7 typedef long long ll;
8 const int MAXN = 1e5 + 10;
9 const int INF = 0x3f3f3f3f;
10 int a[MAXN], n;
11 struct BIT {
12 int mn[MAXN], mx[MAXN];
13
14 void init(void) {
15 memset (mn, INF, sizeof (mn));
16 memset (mx, 0, sizeof (mx));
17 }
18 void add_min(int i, int x) {
19 while (i <= n) {
20 mn[i] = min (mn[i], x); i += i & (-i);
21 }
22 }
23 int query_min(int i) {
24 int res = INF;
25 while (i > 0) {
26 res = min (res, mn[i]); i -= i & (-i);
27 }
28 return res;
29 }
30 void add_max(int i, int x) {
31 while (i <= n) {
32 mx[i] = max (mx[i], x); i += i & (-i);
33 }
34 }
35 int query_max(int i) {
36 int res = 0;
37 while (i > 0) {
38 res = max (res, mx[i]); i -= i & (-i);
39 }
40 return res;
41 }
42 }bit;
43
44 int main(void) {
45 //freopen ("B.in", "r", stdin);
46
47 int t; scanf ("%d", &t);
48 while (t--) {
49 int k; scanf ("%d%d", &n, &k);
50 for (int i=1; i<=n; ++i) {
51 scanf ("%d", &a[i]);
52 }
53
54 ll ans = 0; bit.init ();
55 for (int i=n; i>=1; --i) { //树状数组的特点,倒过来插入,求[i, n]区间
56 bit.add_min (i, a[i]);
57 bit.add_max (i, a[i]);
58 int l = i, r = n;
59 while (l <= r) {
60 int mid = (l + r) >> 1;
61 int MAX = bit.query_max (mid);
62 int MIN = bit.query_min (mid);
63 if (MAX - MIN >= k) r = mid - 1;
64 else l = mid + 1;
65 }
66 ans += l - i;
67 }
68 printf ("%I64d\n", ans);
69 }
70
71 return 0;
72 }
1 /*
2 维护递增和递减的队列,当队首满足条件时,添加个数,再在从后添加元素,否则pop_front
3 */
4 #include <cstdio>
5 #include <algorithm>
6 #include <cstring>
7 #include <queue>
8 using namespace std;
9
10 typedef long long ll;
11 const int MAXN = 1e5 + 10;
12 const int INF = 0x3f3f3f3f;
13 struct Node {
14 int v, p;
15 };
16 int a[MAXN];
17
18 int main(void) {
19 //freopen ("B.in", "r", stdin);
20
21 int t; scanf ("%d", &t);
22 while (t--) {
23 int n, k; scanf ("%d%d", &n, &k);
24 for (int i=1; i<=n; ++i) scanf ("%d", &a[i]);
25
26 deque<Node> Q1, Q2; ll ans = 0; int head = 1;
27 for (int i=1; i<=n; ++i) {
28 Node now = (Node){a[i], i};
29 while (!Q1.empty ()) { //递减 队首max
30 Node tmp = Q1.back ();
31 if (now.v > tmp.v) Q1.pop_back ();
32 else break;
33 }
34 Q1.push_back (now);
35 while (!Q2.empty ()) { //递增 队首min
36 Node tmp = Q2.back ();
37 if (now.v < tmp.v) Q2.pop_back ();
38 else break;
39 }
40 Q2.push_back (now);
41
42 if (i == 1) ans++;
43 else {
44 while (true) {
45 Node big = Q1.front ();
46 Node small = Q2.front ();
47 if (big.v - small.v < k) break;
48 else {
49 if (small.p < big.p) {
50 head = small.p + 1; Q2.pop_front ();
51 }
52 else {
53 head = big.p + 1; Q1.pop_front ();
54 }
55 }
56 }
57 ans += i - head + 1;
58 }
59 }
60 printf ("%I64d\n", ans);
61 }
62
63 return 0;
64 }
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <set> 5 #include <cmath> 6 using namespace std; 7 8 typedef long long ll; 9 const int MAXN = 1e5 + 10; 10 const int INF = 0x3f3f3f3f; 11 multiset<int> S; 12 int a[MAXN]; 13 14 int main(void) { 15 //freopen ("B.in", "r", stdin); 16 17 int t; scanf ("%d", &t); 18 while (t--) { 19 int n, k; scanf ("%d%d", &n, &k); 20 for (int i=1; i<=n; ++i) { 21 scanf ("%d", &a[i]); 22 } 23 24 S.clear (); S.insert (a[1]); 25 int l = 1, r = 2; ll ans = 0; 26 int mn, mx; 27 while (true) { 28 if (S.size ()) { 29 mn = *S.begin (); 30 mx = *S.rbegin (); 31 if (abs (a[r] - mn) < k && abs (a[r] - mx) < k) { 32 ans += S.size (); S.insert (a[r++]); 33 if (r > n) break; 34 } 35 else { 36 if (S.size ()) S.erase (S.find (a[l])); 37 l++; 38 } 39 } 40 else { 41 l = r; S.insert (a[r++]); 42 if (r > n) break; 43 } 44 } 45 46 printf ("%I64d\n", ans + n); 47 } 48 49 return 0; 50 }
编译人生,运行世界!