Homework Introduction

/*
子矩阵的最值
B*B的子矩阵由
B行长度是B的数组构成

1. 求所有长度是B的数组的最值(横向)
例如(1,1) 这个位置存储的是 (1,1) - (1,B)的最值,横向上
2. 对于上述数组,纵向求最值,查表

两次最值,最大值和最小值, 时间复杂度:250*250 * 2
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 255;
int n, b, m, a[N][N];
int q[N], mxc[N][N], mxr[N][N];
int mnc[N][N], mnr[N][N];
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	cin >> n >> b >> m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++) cin >> a[i][j];
	int h = 1, t = 0;
	// 每一行做单调队列 , 求最大值
	for (int i = 1; i <= n; i++) {
		memset(q, 0, sizeof(q));
		h = 1, t = 0;
		for (int j = 1; j <= n; j++) {
			while (h <= t && j - q[h] + 1 > b) h++;
			while (h <= t && a[q[t]][i] <= a[j][i]) t--;
			q[++t] = j;
			if (j >= b)
				mxc[i][j] = a[q[h]][i];
		}
	}
	//  每一列的最大值 , 这样计算出二维的最大值
	for (int i = 1; i <= n; i++) {
		memset(q, 0, sizeof(q));
		h = 1, t = 0;
		for (int j = 1; j <= n; j++) {
			while (h <= t && j - q[h] + 1 > b) h++;
			while (h <= t && mxc[q[t]][i] <= mxc[j][i]) t--;
			q[++t] = j;
			if (j >= b)
				mxr[i][j] = mxc[q[h]][i];
		}
	}
	// 计算二维的最小值
	for (int i = 1; i <= n; i++) {
		memset(q, 0, sizeof(q));
		h = 1, t = 0;
		for (int j = 1; j <= n; j++) {
			while (h <= t && j - q[h] + 1 > b) h++;
			while (h <= t && a[q[t]][i] >= a[j][i]) t--;
			q[++t] = j;
			if (j >= b)
				mnc[i][j] = a[q[h]][i];
		}
	}
	for (int i = 1; i <= n; i++) {
		memset(q, 0, sizeof(q));
		h = 1, t = 0;
		for (int j = 1; j <= n; j++) {
			while (h <= t && j - q[h] + 1 > b) h++;
			while (h <= t && mnc[q[t]][i] >= mnc[j][i]) t--;
			q[++t] = j;
			if (j >= b)
				mnr[i][j] = mnc[q[h]][i];
		}
	}
	while (m--) {
		int r, c;
		cin >> r >> c;
		cout << mxr[r + b - 1][c + b - 1] - mnr[r + b - 1][c + b - 1] << endl;
	}
	return 0;
}
// 对于 k = 1 的情况
// 先把所有的数字按照顺序建立链表
// 从小到大依次删除第 i 个点
// 对于 i,l[i]就是左边第一个大于 i 的位置
// r[i] 就是右边第一个大于 i 的位置
// 贡献就是 a[i]*(i-l[i])*(r[i]-i) , i * 区间个数

// k =1 最大值求和,a[i]*(i-l[i])*(r[i]-i)
// k =2 最大值求和,a[i]*( (l[i]-l[l[i]])*(r[i]-i) + (i-l[i])*(r[r[i]] - r[i]) )
// k 大值求和
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+10;
int n, k;
int pre[N], nxt[N];
int a[N], b[N], c[N];
int cas;
int main() {
	cin >> cas;
	while (cas--) {
		cin >> n >> k;
		nxt[n + 1] = n + 1;
		for (int i = 1; i <= n; i++) {
			int x;
			cin >> x;
			a[x] = i;
			pre[i] = i - 1, nxt[i] = i + 1;
		}
		long long ans = 0;
		for (int i = 1; i <= n; i++) {
			int x = a[i], y = a[i];
			for (int j = 0; j <= k; j++) {
				b[j] = y; //  左边第几个的值
				y = pre[y];
			}
			y = a[i];
			for (int j = 0; j <= k; j++) {
				c[j] = y;
				y = nxt[y];
			}
			for (int j = 1; j <= k; j++) {
				ans += 1ll * (b[j - 1] - b[j]) * (c[k - j + 1] - c[k - j]) * i;
			}
			pre[nxt[x]] = pre[x];
			nxt[pre[x]] = nxt[x];
		}
		cout << ans << endl;
	}
	return 0;
}
// 比自己矮,直接插队
// 第一个比自己高的,贿赂再插队
// 停在比自己第二高的人的后面
// 建立一个链表,
//从低到高依次处理, l[id] 第一个比他高的位置
//l[l[id]] 第一个比他高的位置
//结果 l[l[id]]+1
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n;
struct node {
	int h, id;
	bool operator<(const node a)const {
		return h < a.h;
	}
};
node a[N];
int l[N], r[N], ans[N];
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i].h;
		a[i].id = i;
		l[i] = i - 1;
		r[i] = i + 1;
	}
	sort(a + 1, a + 1 + n);
	// 处理身高最低的人
	for (int i = 1; i <= n; i++) {
		int id = a[i].id;
		ans[id] = l[l[id]] + 1;
		// 删除 id
		r[l[id]] = r[id];
		l[r[id]] = l[id];
	}
	// 输出结果
	for (int i = 1; i <= n; i++)
		cout << ans[i] << endl;
	return 0;
}







#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n;
int pre[N], nxt[N], ans[N];

struct node {
	int x, id; // 当前位置的值和下标
	bool operator < (const node a)const {
		return x < a.x;
	}
};
node a[N];

int pos[N];  // 确定输入顺序和 在链表里面的位置
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i].x;
		a[i].id = i;  // 输入顺序
	}
	// 建立一个 1 - n的双向链表
	for (int i = 1; i <= n; i++) {
		pre[i] = i - 1;
		nxt[i] = i + 1;
	}
	sort(a + 1, a + 1 + n);
	// i = 3 的时候 a[i].id = 5
	for (int i = 1; i <= n; i++)
		pos[a[i].id] = i;
	// 从最后的输入开始处理
	for (int i = n; i >= 1; i--) {
		int id = pos[i];
		int mn = 1e9, mnid = -1;
		if (pre[id] != 0) {
			if (mn > a[id].x - a[pre[id]].x) {
				mn = a[id].x - a[pre[id]].x;
				mnid = a[pre[id]].id;
			}
		}
		if (nxt[id] != n + 1) {
			if (mn > a[nxt[id]].x - a[id].x ) {
				mn = a[nxt[id]].x - a[id].x ;
				mnid = a[nxt[id]].id;
			}
		}
		ans[i] = mnid;
		pre[nxt[id]] = pre[id];
		nxt[pre[id]] = nxt[id];
	}
	for (int i = 2; i <= n; i++)
		cout << ans[i] << " ";
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
int n, x;
map<int, int > mp;
set<int> s;

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> x;
		//cout << x << " ";
		mp[x] = i;
		// 去 set 找一个最接近的
		if (s.empty()) {
			s.insert(x);
			continue;
		}

		else {
			auto it = s.lower_bound(x);
			if (it == s.end())
				cout << mp[*(--it)] << " ";
			else if (it == s.begin())
				cout << mp[*it] << " ";
			else {
				// 前面有,后面也有
				int right = *it;
				int left = *(--it);
				if (right - x >= x - left)
					cout << mp[left] << " ";
				else
					cout << mp[right] << " ";
			}
		}
		s.insert(x);
	}
	return 0;
}
// 双向链表
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
// 编号 1  -n  设 i 就放在 编号 i 上
int pre[N], nxt[N];
int n, q, opt;

// 连接 x  和 y
void connect(int x, int y) {
	nxt[x] = y;
	pre[y] = x;
}

// 解除连接
void disconnect(int x, int y) {
	nxt[x] = 0;
	pre[y] = 0;
}

// 打印 x 所在队列的长度和 元素
void print(int x) {
	int tot = 0, head=x;
	while(pre[head] !=0)
		head = pre[head];
	// 统计个数
	for (int i = head ; i != 0 ; i = nxt[i])
		tot++;
	cout << tot << endl;
	// 从头输出链表
	for (int i = head;  i != 0 ; i = nxt[i])
		cout << i << " ";
}

int main() {
	return 0;
}
// 双向链表
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int val[N], pre[N], nxt[N], idx;
int pos[N], head;

// 将  y 增加到 x 的后面
void insert(int x, int y) {
	x = pos[x]; // 值替换成位置
	++idx;
	val[idx] = y;
	int t  = nxt[x];   // 存储之前  x 的下一个
	nxt[idx] = t;
	nxt[x] = idx;
	pre[idx] = pre[t];
	pre[t] = idx;
}


void init() {
	// 0 和 1 用了
	pre[1] = 0;
	nxt[0] = 1;
	head = 1;
	idx = 1;
	pos[1] = 1;
}

void print() {
	for (int i = nxt[head] ; i != 0 ; i = nxt[i])
		cout << val[i] << " ";
}

int main() {
	init();
	for (int i = 1; i <= 10; i++) {
		insert(1, i + 1);
	}
	print();
	return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N  = 1e5 + 10;
int val[N], nxt[N], idx;
int n, head = 1;
int pos[N];  // pos[i]  = j 代表  数字 i 存储的下标是 j
// map<int,int > pos;
// 将 y 插入在 x 后面
void insert(int x, int y) {
	int it = pos[x];
	++idx;   // index
	val[idx] = y;
	nxt[idx] = nxt[it];
	nxt[it] = idx;
	pos[y] = idx;
}
void insert1(int x) {
	++idx;
	val[idx] = x;
	nxt[idx] = nxt[head];
	nxt[head] = idx;
	pos[x] = idx;
}
void init() {
	head = 1;
	idx = 1;
	nxt[1] = 0;
}
void print() {
	for (int i = nxt[head] ; i != 0; i = nxt[i])
		cout << val[i] << " ";
}
int main() {
	cin >> n;
	init();
	insert1(1);
	for (int i = 2; i <= n; i++)
		insert(1, i);
	print();
	return 0;
}

ll solve(int k) {
	ll ret = 0;
	for (int up = 1; up <= n; up++) { // 枚举上边界
		for (int i = 1; i <= m; i++) {
			b[i] = 0;
			c[i] = 1e9 + 7;
		}
		for (int dn = up ; dn <= n; dn++) { // 枚举下边界
			for (int i = 1; i <= m; i++) {
				b[i] = max(b[i], a[dn][i]);
				c[i] = min(c[i], a[dn][i]);
			}
			// 二维压成一维去计算
      // 一个维度就是  D任务这一题
			ret += calcline(k);
		}
	}
	return ret;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 260;
int n, b, k;
int a[N][N];
int mxr[N][N], mxc[N][N];
int mnr[N][N], mnc[N][N];
int q[N], h, t;

int main() {
	cin >> n >> b >> k;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			cin >> a[i][j];
	// 求最大值数组和最小值数组,写表

	// 求最大值
	// 每一行单调队列
	for (int i = 1; i <= n; i++) {
		h = t = 0;
		for (int j = 1; j <= n; j++) {
			while (h < t && a[i][q[t - 1]] < a[i][j])
				t--;
			q[t++] = j;
			while (h < t && j - q[h] >= b)
				h++;
			if (j >= b)
				mxr[i][j] = a[i][q[h]];
		}
	}

	// 再去列的范畴求最大值 在 mxr 的基础上
	for (int j = 1; j <= n; j++) {
		h = t = 0;
		for (int i = 1 ; i <= n; i++) {
			while (h < t && mxr[q[t - 1]][j] < mxr[i][j])
				t--;
			q[t++] = i;
			while (h < t && i - q[h] >= b)
				h++;
			if (i >= b)
				mxc[i][j] = mxr[q[h]][j];
		}
	}
	
	// 求最小值 mnc  
	

	// 输出结果
	for (int i = 1; i <= k; i++) {
		int x, y;
		cin >> x >> y;
		cout << mxc[x + b - 1][y + b - 1] - mnc[x + b - 1][y + b - 1] << endl;
	}
	return 0;
}
// 限制:能力差小于 k 就行
// 组内成员连续:

// 枚举 r , 维护 最大值,最小值,单调队列
// 判断 最大 - 最小 小于 k ,  ans+= r - l+1; , r固定的,左端点的个数就是区间的个数
//  大于等于 k , l++,  差值小于  k

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, k;
int a[N];
int q1[N], h1, t1;  // 最小
int q2[N], h2, t2;  // 最大
long long ans;
int main() {
	int T ;
	cin >> T;
	while (T--) {
		h1 = t1 = 0; // 初始化
		h2 = t2 = 0;
		cin >> n >> k;
		ans = 0;
		for (int i = 1; i <= n; i++)
			cin >> a[i];

		// 枚举 r
		for (int r = 1, l = 1; r <= n; r++) {
			// 最小值
			while (h1 < t1 && a[q1[t1 - 1]] > a[r] )
				t1--;
			q1[t1++] = r;
			// 最大值
			while (h2 < t2 && a[q2[t2 - 1]] < a[r])
				t2--;
			q2[t2++] = r;
			// 根据差值来, 调整左端点
			while (a[q2[h2]] - a[q1[h1]] >= k) {
				l++;
				if (q1[h1] < l)
					h1++;
				if (q2[h2] < l)
					h2++;
			}
			ans += r - l + 1;
		}
		cout << ans << endl;
	}
	return 0;
}




先排序  x[i] , 

一个单调队列记录左边最高的值
vis1[i] =1:左边有高的

一个单调队列记录右边最高的值
vis2[i] =1:右边有高的

vis1[i] &&vis2[i]  res++;
// 暴力,枚举 r , l  的范围, r-m - r
// sum[r] - sum[l-1], 前缀和

// 在 r 固定的基础上枚举 l ,
// sum[r]  固定的
// sum[r] - sum[l-1] 最大,sum[l-1] 最小

// 求 sum[l-1] 最小,单调队列
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
int n, m, a[N];
long long sum[N];
int q[N], h, t;
long long res;
int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		sum[i] = sum[i - 1] + a[i];
	}
	// 单调队列求得是最小值
	for (int r = 1; r <= n; r++) {
		// 有更优秀的值,
		while (h < t && sum[q[t - 1]] > sum[r])
			t--;
		q[t++] = r;
		// 区间长度
		while (h < t && r - q[h] > m)
			h++;
		res = max(res, sum[r] - sum[q[h]]);
	}
	cout << res;
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, k;
int a[N];
int q[N], h, t;

int main() {
	cin >> n >> k;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	// 单调队列
	for (int i = 1; i <= n; i++) {
		// 当前 i 入队, 之前年级比他大,能力不行的,淘汰
		while (h < t && a[q[t - 1]] > a[i] )
			t--;
		q[t++] = i;  // 当前人入队
		// 看是否有年纪超的
		if (i - q[h] >= k)
			h++;
		if (i >= k)
			cout << a[q[h]] << " ";

	}
	return 0;
}
Status
Done
Problem
13
Open Since
2026-3-1 0:00
Deadline
2026-3-31 23:59
Extension
24 hour(s)