20220706

目录

一.单调栈

二.树状数组


一.单调栈

首先栈的基础操作

入栈:s.push()        出栈:s.pop()     栈顶元素:s.top()       栈中元素个数:s.size()

开栈:stack<node>s

做题步骤:先确定要维护一个怎么样的栈(单调不升/降,递增/减),然后就加亿点点小细节就可以华丽地AK啦~

接下来来看几道例题吧

例题一:

题目描述

给出nn个圆环,每个圆环有内径aiai,外径bibi,高hihi。

圆环xx能放在圆环yy上仅当ay<bx≤byay<bx≤by,问这些圆环最多能搭多高。

输入格式

第一行一个整数n,表示有n个圆环 (1⩽n⩽100000)(1⩽n⩽100000)

接下来n行,每行3个整数,为内径aiai,外径bibi,高hi(1⩽ai,bi,hi⩽109,bi>ai)hi(1⩽ai,bi,hi⩽109,bi>ai)

输出格式

一行,一个整数,表示圆环塔的最大高度。

样例数据

input

3
1 5 1
2 6 2
3 7 3

output

6

input

4
1 2 1
1 3 3
4 6 2
5 7 1

output

4

样例解释:1圆环放在2圆环上,高度为4.

分析:单调栈的入门题,很显然这题我们需要维护一个单调递增栈

#include<bits/stdc++.h>
using namespace std;
long long n,sum,ans;
stack< long long > s;
struct node
{
	long long a,b,h;
}k[100086];
bool cmp(node x,node y)
{
    if(x.b!=y.b) return x.b>y.b; 
    return x.a>y.a;
}
int main()
{
	freopen("standard.in","r",stdin);
	freopen("standard.out","w",stdout);
	cin>>n;
	for(long long i=1;i<=n;i++) cin>>k[i].a>>k[i].b>>k[i].h;
	sort(k+1,k+1+n,cmp);
	ans=sum=k[1].h;
	s.push(1);
	for(long long i=2;i<=n;i++)
	{
		while(!s.empty() && k[s.top()].a>=k[i].b)
		{
			sum-=k[s.top()].h;
			s.pop();
		}
		sum+=k[i].h;
		s.push(i);
		ans=max(ans,sum);
	}
	cout<<ans<<endl;
	return 0;
} 

例题二:

题目描述

贤正的某 N 头奶牛 (1 <= N <= 80,000) 正在过乱头发节!由于每头牛都 意识到自己凌乱不堪的发型, 宁智贤希望统计出能够看到其他牛的头发的牛的数量。

每一头牛 i有一个高度 h[i] (1 <= h[i] <= 1,000,000,000)而且面向东方排成 一排(在我们的图中是向右)。因此,第i头牛可以看到她前面的那些牛的头, (即i+1, i+2,等等),只要那些牛的高度严格小于她的高度。

例如这个例子:

 

牛#1 可以看到她们的发型 #2, 3, 4 牛#2 不能看到任何牛的发型 牛#3 可以看到她的发型 #4 牛#4 不能看到任何牛的发型 牛#5 可以看到她的发型 6 牛#6 不能看到任何牛的发型!

让 c[i] 表示第i头牛可以看到发型的牛的数量;请输出 c[1] 至 c[N]的和。 如上面的这个例子,正确解是3 + 0 + 1 + 0 + 1 + 0 = 5。

输入格式

  • Line 1: 牛的数量 N。

  • Lines 2..N+1: 第 i+1 是一个整数,表示第i头牛的高度。

输出格式

Line 1: 一个整数表示c[1] 至 c[N]的和。

样例数据

input

6
10
3
7
4
12
2

output

5

分析:与上题类似,不过本题需要维护的是单调递减栈

#include<bits/stdc++.h>
using namespace std;
long long n,ans;
long long h[10000086];
stack< long long > s;
int main()
{
	freopen("badhair.in","r",stdin);
	freopen("badhair.out","w",stdout);
	cin>>n;
	for(long long i=1;i<=n;i++) cin>>h[i];
	for(long long i=1;i<=n;i++)
	{
		while(!s.empty() && s.top()<=h[i])
		{
			s.pop();
		}
		ans+=s.size();
		s.push(h[i]);
	}
	cout<<ans<<endl;
	return 0;
}

例题三:

题目描述

现在有N(0<=N<=500 000)个人在一起排队,他们的身高分别为A1,...,AN(0<=Ai<=231},i=1~N)我们规定A能看到B当且仅当AB之间没有比A高的人,那么有多少对人能够相互看到呢?

输入格式

第一行一个非负整数N,第二行N个非负整数A1,...,AN,之间用空格分隔

输出格式

一行一个非负整数,表示相互能看到的人的对数

样例

样例输入1

2
2 2

样例输出1

1

样例输入2

3
3 2 1

样例输出2

2

分析:单调递减栈,需要特别考虑相同时的情况

#include<bits/stdc++.h>
using namespace std;
long long n,same;
long long a[500100];
long long ans;
stack< long long >s;
int main()
{
	freopen("stack.in","r",stdin);
	freopen("stack.out","w",stdout);
	scanf("%d",&n);
	for(long long i=1;i<=n;i++) scanf("%d",&a[i]);
	s.push(a[1]);
	for(long long i=2;i<=n;i++)
	{
		if(s.top()>a[i])
		{
			ans++;
			s.push(a[i]);
		}
		else 
		{
			while(!s.empty() && s.top()<a[i])
			{
				ans++;
				s.pop();
			}
			same=0;
			while(!s.empty() && s.top()==a[i])
			{
				same++;
				ans++;
				s.pop();
			}
			if(!s.empty()) ans++;
			for(long long j=1;j<=same;j++) s.push(a[i]);
			s.push(a[i]);
		}
	}
	cout<<ans<<endl;
	return 0;
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值