牛客补题 骚区间

骚区间

题目链接

题意

给一个数组,问有多少个连续子序列l ~ r满足 a[l]是这个区间的次小值a[r]是这个区间的次大值。

题解

刚开始上去没什么想法,但是后来发现
对于一个数,
1、当这个数是左边界时,从他右边比他大的第一个开始到比他大的第二个数之间的数都可能是右边界。
2、当这个数是右边界时,他的左边比他小的第一个数到比他小的第二个数之间都可能是左边界。
但是这两种情况混一下我就不知道该怎么处理了。。。
可能见的题目还是少,比较菜把。
可以用树状数组维护。
树状数组里放的是有多少值当左边界的时候,右边界可能取得到这个位置。。
可能有点绕。。说不清,或许是我理解的不太到位。
设当前位置 i 是左边界的时候x ~ y 的值可能是右边界。然后 遍历到x的时候 把i 这个位置加进去,遍历到y的时候把i 这个位置减去,像差分一样。
然后 统计的时候就可以按编号2 中的值统计,也就是 当前位置是右边界时,查询左边界有多少 然后加进去。
代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void wenjian(){freopen("concatenation.in","r",stdin);freopen("concatenation.out","w",stdout);}
void tempwj(){freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{bool operator()(const pii & a, const pii & b){return a.second > b.second;}};
int lb(int x){return  x & -x;}
typedef set<int>::iterator SI;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 9901;
 
const int M = 10000007;
const int maxn = 1e6+5;
int a[maxn];
int pos[maxn];
set<int> ss;
std::vector<int> vl[maxn];
std::vector<int> vr[maxn];
int pl[maxn];
int pr[maxn];
int tree[maxn];
int n;
void add(int x, int num)
{
	while(x <= n)
	{
		tree[x] += num;
		x += lb(x);
	}
}

int query(int x)
{
	int ans =0 ;
	while(x > 0)
	{
		ans += tree[x];
		x -= lb(x);
	}
	return ans;
}

int main()
{
	
	scanf("%d",&n);
	for (int i = 1; i <= n; i ++ )
	{
		scanf("%d",&a[i]);
		pos[a[i]] = i;
	}
	for (int i = 1; i <= n; i ++ )
	{
		ss.insert(pos[i]);
		SI x = ss.upper_bound(pos[i]);
		if(x != ss.end())
		{
			vl[*x].pb(pos[i]);
			x ++ ;
			if(x != ss.end())
			{
				int t = *x;
				vr[t - 1].pb(pos[i]);
			}
		}
	}
	ss.clear();
	for (int i = n; i >= 1; i -- )
	{
		ss.insert(-pos[i]);
		SI x = ss.upper_bound(-pos[i]);
		if(x != ss.end())
		{
			pr[pos[i]] = - *x;
			x ++ ;
			if(x != ss.end())
			{
				pl[pos[i]] = - *x + 1;
			}
		}
	}

	ll ans = 0;
	for (int i = 1; i <= n; i ++ )
	{
		for (int j = 0; j < vl[i].size(); j ++ )
		{
			add(vl[i][j],1);
		}
		// printf("11111111111111");
		// printf("%d %d %d\n",i,pl[i],pr[i]);
		ans += query(pr[i]) - query(pl[i] - 1);
		for (int j = 0; j < vr[i].size(); j ++ )
		{
			add(vr[i][j],-1);
		}
	}
	printf("%lld\n",ans);
}

你可能感兴趣的:(做题笔记)