线段树+循环单点修改,本地IDE debug逻辑没问题,自己造的数据也都没问题
#include<iostream>
#include<vector>
#include<math.h>
#include<set>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
/*线段树(segment Tree)是一种树状数组,用于区间操作。
* 结构为完全二叉树,结点值是区间之和
* 根结点为整个区间,左子树为左半区间,右子树为右区间
*/
/*
* 区间修改懒标记的思想是:将修改效果全部施加到公共父结点上,但不修改子结点
* 只有当访问子结点时,将懒标记下传并修改值
* 例如,修改区间[L,R]所有元素
* 找到所有完全包含于[L,R]的尽可能上层的所有子结点,即最大分割
* 将这些结点懒标记
*/
//线段树结点
class segmentTreeNode {
public:
//线段左右端点
int start;
int end;
//结点值,可以存储区间相关的一些属性,如最值、求和等
//这里以取最大值为例
int data;
//延迟更新标记
int mark;
segmentTreeNode* left;
segmentTreeNode* right;
segmentTreeNode(int start, int end, int data) {
this->start = start;
this->end = end;
this->data = data;
this->left = this->right = nullptr;
this->mark = 0;
}
void outPut() {
cout << "区间:" << this->start << "~" << this->end <<",";
cout << "\t" << "val=" << this->data <<"\t" <<endl;
}
};
//线段树
class segmentTree {
private:
segmentTreeNode* treeBulider(int left, int right) {
if (left > right) return nullptr;
else if (left == right) {
return new segmentTreeNode(left, right, vec[left]);
}
else {
int mid = (left + right) >> 1;
segmentTreeNode* subRoot = new segmentTreeNode(left, right, 0);
subRoot->left = treeBulider(left, mid);
subRoot->right = treeBulider(mid + 1, right);
subRoot->data = min(subRoot->left->data, subRoot->right->data); //pushUp操作
return subRoot;
}
}
public:
vector<int> vec;
segmentTreeNode* root;
segmentTree(vector<int> vec, int start, int end) {
this->vec = vec;
this->root = treeBulider(start, end);
}
//可视化
void show() {
queue<segmentTreeNode*> Q;
Q.push(this->root);
segmentTreeNode* curNode = nullptr;
//记录层数
int count = 1;
while (!Q.empty()) {
//记录结点数
int size = Q.size();
//同一层
cout << "第" << count << "层" << endl;
while (size-- > 0) {
curNode = Q.front();
curNode->outPut();
Q.pop();
if (curNode->left)Q.push(curNode->left);
if (curNode->right) Q.push(curNode->right);
}
//换层
count++;
}
}
//单点修改
void changOne(segmentTreeNode* root,int pos,int newVal) {
//不在当前区间
if (pos<root->start || pos>root->end) return;
//在当前点
if (root->start == root->end&&root->start==pos) {
root->data = newVal;
this->vec[pos] = newVal;
return;
}
int mid = (root->start + root->end) >> 1;
if(pos>mid) changOne(root->right, pos, newVal);
else changOne(root->left, pos, newVal);
//passUp
root->data = min(root->left->data, root->right->data);
}
//区间查找
int queryMin(int start, int end, segmentTreeNode* root) {
//正好覆盖
if (root->start >= start && root->end <= end)
return root->data;
if (root->start > end || root->end < start)
return 9999999;
//每当查询到任一个结点,懒标记下传
//pushdown(root);
//当前查询区间中点
int mid = (root->start + root->end) >> 1;
int ll = 9999999, rr = 9999999;
//与左侧区间有交点
if (start <= mid) {
ll = queryMin(start, end, root->left);
}
if (end > mid)
rr = queryMin(start, end, root->right);
return min(ll, rr);
}
};
int main() {
int n = 0, m = 0;
cin >> n >> m;
vector<int> classrooms(n + 1);
for (int i = 1; i <= n; i++) {
cin >> classrooms[i];
}
vector<vector<int>> vec(m+1,vector<int>(3));
for (int i = 1; i <= m; i++) {
for (int j = 0; j < 3; j++) {
cin >> vec[i][j];
}
}
segmentTree* tree = new segmentTree(classrooms, 1, n);
for (int i = 1; i <= m; i++) {
int st = vec[i][1], ed = vec[i][2], qu = vec[i][0];
int mins = tree->queryMin(st, ed, tree->root);
cout << i<<"订单" << endl;
tree->show();
if (mins < qu) {
cout << -1 << endl;
cout << i;
return 0;
}
for (int j = st; j <= ed; j++) {
classrooms[j] -= qu;
tree->changOne(tree->root, j, classrooms[j]);
}
cout << endl;
}
cout << 0;
return 0;
}