1.创建优先队列和string(用于记录指令)。
2.循环输入字符串指令,判断分支操作。
#include
#include
#include
using namespace std;
int main() {
priority_queue<int> maxHeap; // 默认是最大堆
string command;
int k;
while (true) {
cin >> command;
if (command == "insert") {
cin >> k;
maxHeap.push(k); // 将元素插入堆中
} else if (command == "extract") {
if (!maxHeap.empty()) {
cout << maxHeap.top() << endl; // 输出堆顶元素
maxHeap.pop(); // 移除堆顶元素
} else {
cout << "Heap is empty" << endl; // 如果堆为空,输出提示信息
}
} else if (command == "end") {
break; // 结束程序
} else {
cout << "Invalid command" << endl; // 处理无效命令
}
}
return 0;
}
#include
#include
#include
using namespace std;
const int MAXN = 1e5 + 10;
const int MAXLOG = 20; // log2(MAXN) 的上限
int st[MAXN][MAXLOG]; // ST 表
int log2Table[MAXN]; // log2Table[i] 表示 i 的以 2 为底的对数的整数部分
// 快速读入函数
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
// 预处理 log2Table
void preprocessLog2Table(int n) {
for (int i = 2; i <= n; ++i) {
log2Table[i] = log2Table[i >> 1] + 1;
}
}
// 预处理 ST 表
void preprocessST(int n, const vector<int>& arr) {
for (int i = 0; i < n; ++i) {
st[i][0] = arr[i];
}
for (int j = 1; (1 << j) <= n; ++j) {
for (int i = 0; i + (1 << j) - 1 < n; ++i) {
st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
}
// 查询区间 [l, r] 的最大值
int query(int l, int r) {
int j = log2Table[r - l + 1];
return max(st[l][j], st[r - (1 << j) + 1][j]);
}
int main() {
int n = read(), m = read();
vector<int> arr(n);
for (int i = 0; i < n; ++i) {
arr[i] = read();
}
preprocessLog2Table(n);
preprocessST(n, arr);
while (m--) {
int l = read() - 1, r = read() - 1; // 输入的区间是 1-based,转换为 0-based
//cout << query(l, r) <<"\n";
printf("%d\n",query(l, r));
}
return 0;
}
使用优先队列读取数据,通过top(),找出最小的两个元素,相加并记录为ans,重复此过程直到所有元素都被弹出队列。
#include
using namespace std;
int pile[10005]={0};
int len=0;
int main()
{
int n;
scanf("%d",&n);
priority_queue<int,vector<int>,greater<int> > q;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
q.push(x);
}
int ans=0;
while(q.size()!=1)
{
int a1=q.top();
q.pop();
int a2=q.top();
q.pop();
ans+=a1+a2;
q.push(a1+a2);
}
printf("%d\n",ans);
}
#include
using namespace std;
int a[100]={0};
//元素值为0表示未出局
//i既代表数组的下标,也代表每个人的编号
//k是用来计数的,一旦k的值达到m,代表此人需要出局,并且k需要重新计数,这样才能够找出所有需要出局的人
//数组的0代表未出局的人,数组非0代表出局的人,未出局的人需要报数,出局的人不需要报数
int main()
{
int m,n,i=1,sum=0,k=0;//sum是出局人数
cin>>n>>m;
while(n!=sum)//当出局人数!=n 进入
{
if(i>n)//当i>n的时候从1重新报数
i=1;
if(a[i]==0)//只有当元素值为0进入 否则直接++
{
k++;//k计数器++
if(k==m)
{
sum++;
k=0;//k从0开始报数
a[i]=1;//元素值变1 表示出局 往后不再报数
cout<<i<<" ";
}
}
i++;
}
return 0;
}
首先循环读入数组a[],
f[]数组用于记录仰望对象。
由于向右看齐,最后一个元素必定没有仰望对象,所以从最后开始倒序处理。
单调栈中仅保留最大的对象的下标,其他比它小的元素弹出。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define frep(i,x,y) for(int i=x;i>=y;i--)
const int N=100005;
int n;
stack<int> s;
int a[N];
int f[N];
int main()
{
scanf("%d",&n);
rep(i,1,n)
scanf("%d",&a[i]);
frep(i,n,1)
{
while(!s.empty()&&a[s.top()]<=a[i]) s.pop();
if(!s.empty()) f[i]=s.top();
else f[i]=0;
s.push(i);
}
rep(i,1,n) printf("%d\n",f[i]);
return 0;
}
从左到右入队,入队的信息为(高度,下标位置)
如果后入队的高度大于前面的高度,则将前面的元素弹出,并将它们的仰望对象= 后入队的下标
最后剩下的元素仰望对象= 0.
#include
using namespace std;
int n,f[100010];
struct node{
int num;
int id;
}e;
deque <node> q;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
int a;
scanf("%d",&a);
while (!q.empty()&&q.back().num<a) f[q.back().id]=i,q.pop_back();
//找比它小的数,成为这些数的仰望对象
e.num=a; e.id=i;
q.push_back(e); //入队
}
for (int i=1;i<=n;i++) printf("%d\n",f[i]);
return 0;
}
//递推关系为f[i][j]=f[f[i][j−1]][j−1]
#include
using namespace std;
const int MAXN = 2e5+5;
int ans[MAXN];//记录每个士兵的答案
int n,m;//n:士兵数 m:站点数
int f[MAXN*2][20];//由于使用双倍链,所以maxn需要*2.
struct node {
int id; // 士兵编号
int l, r; // 奔袭区间的左右端点,已转换为“连续区间”的形式
} s[MAXN*2];
bool cmp(node a, node b) {
return a.l < b.l;
}//比较士兵的左端点,用于排序。
void pre() {
for (int i = 1, p = i; i <= 2 * n; i++) {
while (p <= 2 * n && s[p].l <= s[i].r) {
p++;
}
// p-1 就是满? s[p-1].l <= s[i].r 的最后?个区间
f[i][0] = p - 1;
}
// 构造倍增表 f[i][j]
for (int i = 1; i < 20; i++) {
for (int j = 1; j <= 2 * n; j++) {
f[j][i] = f[f[j][i-1]][i-1];
}
}
}
void solve(int k) {
int rr = s[k].l + m;//目标终点
int tot = 1; //使用的士兵个数
int p = k; //记录原始士兵编号,用于给答案数组赋值
for (int i = 19; i >= 0; i--) {
if (f[k][i] != 0 && s[f[k][i]].r < rr) {
tot += (1 << i);
k = f[k][i];
}
}
//+1确保覆盖一圈
ans[s[p].id] = tot + 1;
}
int main(){
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d %d", &s[i].l, &s[i].r);
//处理左端点比右端点大的士兵
if (s[i].r < s[i].l) {
s[i].r += m;
}
s[i].id = i; // 记录原始编号
}
//对士兵根据左端点从小到大排序
sort(s + 1, s + 1 + n, cmp);
//将所有士兵复制一份到新增的m区间
for (int i = 1; i <= n; i++) {
s[i + n] = s[i]; // 复制原区间
s[i + n].l = s[i].l + m; // 左端点右移 m
s[i + n].r = s[i].r + m; // 右端点右移 m
}
pre();
for (int i = 1; i <= n; i++) {
solve(i);
}
for (int i = 1; i <= n; i++) {
printf("%d ", ans[i]);
}
return 0;
}
特性:后进先出 ,只能处理栈顶元素
特性:先进先出,仅支持查询或删除第一个加入的元素,添加进去的元素为最后一个元素。
类型:二叉堆
特性:插入元素后会根据优先级自动排序。
priority_queue<int> q;
里面的元素从小到大排列,top元素为队列最后一个元素。
小根堆写法 priority_queue<int, vector<int>,greater<int> > p;
greater表示大的数放前面。
可重复贡献问题在实际应用中具有广泛的用途,尤其是在需要高效处理区间查询的场景中。以下是一些实际应用的例子: