[51Nod1482] 部落信号

题意:有N个部落围成一圈,每个部落都有一个高度,如果两个部落之间的部落高度都低于这两个部落的高度,那么这两个部落则互相可见,一个部落从顺时针或逆时针方向看到另一个部落都算互相可见

题解:

单调栈

一个部落从顺时针方向看到与它互相可见的部落,一定是一段连续递增的序列,逆时针同理

这就很像单调栈的维护方式

先把最大的点砍掉,断环为链

然后对于每个点顺时针和逆时针的贡献都用单调栈统计一次

最后再把最大点的贡献算一遍

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long  
using namespace std;

const int N = 1000010;

int n,mx,top;
int a[N],v[N],stk[N],same[N],bj[N],l[N],r[N];
ll ans;

int gi() {
	int x=0,q=1; char ch=getchar();
	while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
	if(ch=='-') q=-1;
	while(ch>='0' && ch<='9') x=10*x+ch-'0',ch=getchar();
	return x*q;
}

int main() {
	n=gi();
	for(int i=1; i<=n; i++) {
		a[i]=gi();
		if(!mx || a[i]>a[mx]) mx=i;
	}
	for(int i=mx; i<=n; i++) v[++top]=a[i];
	for(int i=1; i<=mx-1; i++) v[++top]=a[i];
	top=0;
	for(int i=2; i<=n; i++) {
		while(top && v[i]>=v[stk[top]]) top--;
		l[i]=stk[top];
		stk[++top]=i;
	}
	top=0,stk[top]=n+1;
	for(int i=n; i>=2; i--) {
		while(top && v[i]>=v[stk[top]]) {
			if(v[i]==v[stk[top]]) same[i]=same[stk[top]]+1;
			top--;
		}
		r[i]=stk[top];
		stk[++top]=i;	
	}
	for(int i=2; i<=n; i++) {
		if(l[i]>0) ans++;
		if(r[i]<=n) ans++;
		ans+=same[i];
	}
	mx=0;
	for(int i=2; i<=n; i++) {
		if(v[i]>=mx) bj[i]=1;
		mx=max(mx,v[i]);
	}
	mx=0;
	for(int i=n; i>=2; i--) {
		if(v[i]>=mx) bj[i]=1;
		mx=max(mx,v[i]);
	}
	for(int i=2; i<=n; i++) ans+=bj[i];
	printf("%lld", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/HLXZZ/p/7535720.html