cpp
复制代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N=2e6+5;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n, k;
cin >> n >> k;
vector<ll> a(n);//不开long long 见祖宗
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
// 存储每个窗口的最小值
vector<ll> minresult;
// 存储每个窗口的最大值
vector<ll> maxresult;
deque<int> mindeque; // 维护单调递增队列,队首为当前窗口最小值的索引
deque<int> maxdeque; // 维护单调递减队列,队首为当前窗口最大值的索引
for (int i = 0; i < n; ++i) {
// 维护最小值队列
// 移除所有大于当前元素的元素,保持队列递增
while (!mindeque.empty() && a[i] <= a[mindeque.back()]) {
mindeque.pop_back();
}
mindeque.push_back(i);
// 移除超出窗口范围的元素
while (mindeque.front() <= i - k) {
mindeque.pop_front();
}
// 维护最大值队列
// 移除所有小于当前元素的元素,保持队列递减
while (!maxdeque.empty() && a[i] >= a[maxdeque.back()]) {
maxdeque.pop_back();
}
maxdeque.push_back(i);
// 移除超出窗口范围的元素
while (maxdeque.front() <= i - k) {
maxdeque.pop_front();
}
// 当窗口大小达到k时,开始记录结果
if (i >= k - 1) {
minresult.push_back(a[mindeque.front()]);
maxresult.push_back(a[maxdeque.front()]);
}
}
// 输出最小值结果
for (int i = 0; i < minresult.size(); ++i) {
if (i > 0) cout << " ";
cout << minresult[i];
}
cout << "\n";
// 输出最大值结果
for (int i = 0; i < maxresult.size(); ++i) {
if (i > 0) cout << " ";
cout << maxresult[i];
}
cout << "\n";
return 0;
}
cpp
复制代码
#include <iostream>
using namespace std;
using ll =long long ;
const int N = 30010;
// pre[i]:存储第i号战舰的父节点索引
// rank0[i]:存储第i号战舰到其父节点的距离(即中间相隔的战舰数量)
// size0[i]:当i为根节点时,存储该队列的总战舰数量
int pre[N], rank0[N], size0[N];
/**
* 初始化并查集
* 每个战舰初始时自成一列(父节点为自身)
* 距离为0(自身到自身无距离)
* 队列大小为1(仅包含自己)
*/
void init() {
for (int i = 1; i < N; ++i) {
pre[i] = i; // 父节点指向自身
rank0[i] = 0; // 到自身的距离为0
size0[i] = 1; // 初始队列大小为1
}
}
/**
* 查找根节点并进行路径压缩
* 路径压缩过程中会更新距离,确保rank[x]始终表示x到根节点的距离
*/
int find(int x) {
// 如果x不是根节点,递归查找其父节点的根节点
if (pre[x] != x) {
// 暂存原父节点,用于后续距离计算
int root = find(pre[x]);
// 路径压缩:将x的父节点直接指向根节点
// 同时更新x到根节点的总距离(x到原父节点的距离 + 原父节点到根节点的距离)
rank0[x] += rank0[pre[x]];
pre[x] = root;
}
return pre[x];
}
/**
* 合并两个战舰队列
* 将x所在的整个队列移动到y所在队列的尾部
*/
void join(int x, int y) {
// 找到x和y所在队列的根节点
int rootX = find(x);
int rootY = find(y);
// 将rootX所在队列合并到rootY所在队列的尾部
pre[rootX] = rootY;
// rootX到新父节点rootY的距离为rootY队列的大小(排在所有原有战舰之后)
rank0[rootX] = size0[rootY];
// 更新合并后队列的总大小
size0[rootY] += size0[rootX];
}
int main() {
// 初始化并查集
init();
int T; // 指令总数
cin >> T;
while (T--) {
char cmd; // 指令类型(M或C)
int i, j; // 指令涉及的战舰编号
cin >> cmd >> i >> j;
if (cmd == 'M') {
// 处理合并指令:将i所在队列合并到j所在队列尾部
join(i, j);
} else {
// 处理查询指令:检查i和j是否在同一队列
int rootI = find(i);
int rootJ = find(j);
if (rootI != rootJ) {
// 根节点不同,不在同一队列
cout << -1 << endl;
} else {
// 根节点相同,在同一队列
// 两艘战舰之间的数量 = 距离差的绝对值 - 1
cout << abs(rank0[i] - rank0[j]) - 1 << endl;
}
}
}
return 0;
}
cpp
复制代码
#include <iostream>
using namespace std;
const int MAXN = 1001; // 最大城镇数
int pre[MAXN]; // 存储每个节点的父节点
// 查找根节点,带路径压缩
int find(int x) {
// 如果x不是根节点,递归查找其父节点的根节点
if (pre[x] != x) {
// 路径压缩:将x的父节点直接指向根节点
pre[x] = find(pre[x]);
}
return pre[x];
}
// 合并两个集合
void join(int x, int y) {
int rootX = find(x); // 找到x的根节点
int rootY = find(y); // 找到y的根节点
if (rootX != rootY) {
// 将一个集合的根节点指向另一个集合的根节点,实现合并
pre[rootY] = rootX;
}
}
int main() {
int n, m;
while (cin >> n && n != 0) { // 读取城镇数,0表示结束
cin >> m; // 读取道路数
// 初始化并查集:每个节点的父节点是自身
for (int i = 1; i <= n; ++i) {
pre[i] = i;
}
// 处理每条道路,合并连通的城镇
for (int i = 0; i < m; ++i) {
int a, b;
cin >> a >> b;
join(a, b);
}
// 统计连通分量的数量
int count = 0;
for (int i = 1; i <= n; ++i) {
// 如果节点是根节点(父节点是自身),说明是一个新的连通分量
if (pre[i] == i) {
count++;
}
}
// 最少需要建设的道路数 = 连通分量数 - 1
cout << count - 1 << endl;
}
return 0;
}
cpp
复制代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long ;
int main() {
int n;// 读取发射站的数量n
cin >> n;
// 定义三个动态数组:
// h[i] 存储第i个发射站的高度
// v[i] 存储第i个发射站的能量值
// sum[i] 存储第i个发射站接收到的总能量
// 数组下标从1开始,方便与发射站编号对应
vector<int> h(n + 1), v(n + 1), sum(n + 1);
// 定义一个栈,用于存储发射站的索引(编号)
// 栈中元素对应的发射站高度保持单调递减的特性
stack<int> st;
// 依次处理每个发射站
for (int i = 1; i <= n; i++) {
// 读取当前发射站的高度和能量值
cin >> h[i] >> v[i];
// 栈不为空,且栈顶发射站的高度 < 当前发射站的高度时:
// 说明栈顶发射站右边最近的更高发射站就是当前发射站
// 因此栈顶发射站的能量会被当前发射站接收
while (!st.empty() && h[st.top()] < h[i]) {
// 当前发射站接收栈顶发射站的能量
sum[i] += v[st.top()];
// 弹出栈顶元素:因为它已经找到右边更高的发射站,不会再影响后续元素
st.pop();
}
// 经过上面的循环后,如果栈不为空:
// 说明栈顶发射站的高度 > 当前发射站的高度
// 即栈顶发射站是当前发射站左边最近的更高发射站
// 因此当前发射站的能量会被栈顶发射站接收
if (!st.empty()) {
sum[st.top()] += v[i];
}
// 将当前发射站的索引入栈,供后续发射站判断
st.push(i);
}
// 找出所有发射站中接收能量最多的值
int cnt = 0; // 用于存储最大接收能量值
for (int i = 1; i <= n; i++) {
// 更新最大值
cnt = max(cnt, sum[i]);
}
// 输出结果
cout << cnt << endl;
return 0;
}
cpp
复制代码
#include <bits/stdc++.h>
using namespace std;
using ll= long long ;
int main() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
stack<int> st; // 存储柱子索引,栈中元素对应高度单调递减
ll res = 0;
for (int i = 0; i < n; ++i) {
// 当当前柱子高度大于栈顶柱子高度时,弹出栈顶并计算积水
while (!st.empty() && a[i] > a[st.top()]) {
ll top = st.top();
st.pop();
if (st.empty()) break; // 栈空则无法形成积水
ll left = st.top(); // 左侧边界索引
ll h = min(a[i], a[left]) - a[top]; // 积水高度
ll w = i - left - 1; // 积水宽度
res += h * w; // 累加积水量
}
st.push(i);
}
cout << res << endl;
return 0;
}
cpp
复制代码
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> heights(n);
for (int i = 0; i < n; ++i) {
cin >> heights[i];
}
// 在数组首尾添加0,简化边界处理(确保所有柱子都能被计算)
heights.insert(heights.begin(), 0);
heights.push_back(0);
stack<int> stk; // 单调栈:存储柱子索引,确保索引对应高度递增
int maxarea = 0; // 存储最大矩形面积,变量名改为maxarea
for (int i = 0; i < heights.size(); ++i) {
// 当当前高度小于栈顶索引对应的高度时,弹出栈顶并计算面积
while (!stk.empty() && heights[i] < heights[stk.top()]) {
int height = heights[stk.top()]; // 弹出栈顶元素的高度(当前计算的矩形高度)
stk.pop();
// 宽度 = 当前索引(右边界) - 新栈顶索引(左边界) - 1
int width = i - stk.top() - 1;
// 更新最大面积
maxarea = max(maxarea, height * width);
}
// 压入当前索引,维持栈的递增特性
stk.push(i);
}
// 输出最终结果
cout << maxarea << endl;
return 0;
}