[ABC372D] Buildings 题解

很容易发现正着做怎么做都是 O(n2)O(n^2) 的,于是我们想到了 P2947,仔细看会发现它们很像,我们就有了一种想法:反着想,对于每个建筑,从左边一直找出建筑,计数器 +1+1,直到找到更高的建筑,记录下来,那么左边的几个建筑答案就会增加 11

知道了思路就可以思考方法了。从左边一直找出建筑,直到找到更高的建筑可以使用单调栈,区间加 11 可以用差分,最后做个前缀和即可。

贴个代码:

#include<bits/stdc++.h>
using namespace std;
int n, a[200005], ans[200005], st[200005], head, c[200005];
map<int, int> mp;
int main(){
	cin >> n;
	for(int i = 1; i <= n; i ++) cin >> a[i], mp[a[i]] = i;//map是用来方便找出栈顶序号,也可以用 pair
	for(int i = 1; i <= n; i ++){
		while(head && st[head] < a[i]) ans[i] = ans[i] + ans[mp[st[head --]]] + 1;//答案加栈顶的答案再加上栈顶
		st[++ head] = a[i];
	}//上面就是普通的单调栈,这是我习惯的写法,比较好理解,其实是一样的
	for(int i = 1; i <= n; i ++) ++ ans[i];
	for(int i = 1; i <= n; i ++){
		c[i - ans[i]] ++;//差分
		c[i] --;//差分
	}
	for(int i = 1; i <= n; i ++) c[i] += c[i - 1];//前缀和求答案
	for(int i = 1; i <= n; i ++) cout << c[i] << " ";
	return 0;
}

使用 pair 的代码:

#include<bits/stdc++.h>
using namespace std;
int n, a[200005], ans[200005], head, c[200005];
pair<int, int> st[200005];
int main(){
	cin >> n;
	for(int i = 1; i <= n; i ++) cin >> a[i];
	for(int i = 1; i <= n; i ++){
		while(head && st[head].first < a[i]) ans[i] = ans[i] + ans[st[head --].second] + 1;
		st[++ head] = {a[i], i};
	}
	for(int i = 1; i <= n; i ++) ++ ans[i];
	for(int i = 1; i <= n; i ++){
		c[i - ans[i]] ++;
		c[i] --;
	}
	for(int i = 1; i <= n; i ++) c[i] += c[i - 1];
	for(int i = 1; i <= n; i ++) cout << c[i] << " ";
	return 0;
}

posted on 2024-09-23 22:02  zhangzirui66  阅读(8)  评论(0)    收藏  举报  来源

导航