zoukankan      html  css  js  c++  java
  • 51Nod

    题目链接

    题目大意

      略

    解题思路

      如果一个子段合法,那么必然左边的值作为最小值的区域和右边的值作为最大值的区域都能包含彼此,所以用单调栈求出右边的值作为最大值能到达左边的下标的最小值(l_i),以及左边的值作为最小值能够到达右边的下标的最大值(r_i),然后将前者排序,按从左到右的顺序遍历每个数,将所有(l_i < i)的数的位置加入树状数组,查询在([i, r_i])范围内有多少点即为当前点作为区间左端点的合法区间数量。

    代码

    const int maxn = 2e5+10;
    const int maxm = 5e6+10;
    int n, arr[maxn], c[maxn];
    P l[maxn], r[maxn];
    void add(int x) {
    	while(x<=n) {
    		++c[x];
    		x += x&-x;
    	}
    }
    int ask(int x) {
    	int sum = 0;
    	while(x) {
    		sum += c[x];
    		x -= x&-x;
    	}
    	return sum;
    }
    int main() {
    	cin >> n;
    	for (int i = 1 ; i<=n; ++i) scanf("%d", &arr[i]);
    	stack<int> sk;
    	for (int i = 1; i<=n; ++i) {
    		while(!sk.empty() && arr[sk.top()]<=arr[i]) sk.pop();
    		if (sk.empty()) l[i].x = 1;
    		else l[i].x = sk.top()+1;
    		l[i].y = i;
    		sk.push(i);
    	}
    	while(!sk.empty()) sk.pop();
    	for (int i = n; i>=1; --i) {
    		while(!sk.empty() && arr[sk.top()]>=arr[i]) sk.pop();
    		if (sk.empty()) r[i].x = n;
    		else r[i].x = sk.top()-1;
    		r[i].y = i;
    		sk.push(i);
    	}
    	sort(l+1, l+n+1);
    	int tot = 1; ll ans = 0;
    	for (int i = 1; i<=n; ++i) {
    		while(tot<=n && l[tot].x<=i) add(l[tot++].y);
    		ans += ask(r[i].x)-ask(r[i].y-1);
    	}
    	cout << ans << endl;
        return 0;	
    }
    
  • 相关阅读:
    xtrabackup执行备份要拥有的权限
    CentOS 7 下yum安装xtrabackup备份工具
    MySQL read_only选项的作用
    Linux进程管理命令
    MySQL二进制日志中保存的上下文信息
    MySQLdb的安装
    MySQL The password hash doesn't have the expected format.
    web框架本质
    进程和线程
    good blog
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/14551623.html
Copyright © 2011-2022 走看看