51NOD 1962 区间计数 单调栈+二分 / 线段树+扫描线

Posted Meek

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51NOD 1962 区间计数 单调栈+二分 / 线段树+扫描线相关的知识,希望对你有一定的参考价值。

 区间计数
 
基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80
 

两个数列 {An} 技术分享, {Bn} 技术分享,请求出Ans, Ans定义如下:

 

Ans:=Σni=1Σnj=i[max{Ai,Ai+1,...,Aj}=max{Bi,Bi+1,...,Bj}] 

 

注:[ ]内表达式为真,则为1,否则为0.

 
 
1N3.5×1051Ai,BiN 
 
样例解释:
7个区间分别为:(1,4),(1,5),(2,4),(2,5),(3,3),(3,5),(4,5)
Input
第一行一个整数N
第二行N个整数Ai
第三行N个整数Bi
Output
一行,一个整数Ans
Input示例
5
1 4 2 3 4
3 2 2 4 1
Output示例
 
7
 
题解:
  第一种做法是 两个单调栈 + 二分
  两个数都同时维护一个单调递减的 栈
  当元素出栈是我们可以确定以其为最大值所能掌管的一段区间,那么 在对应另一个栈内通过二分找到此值也能掌管一段区间
  求出区间交就可以了
  第二种做法比较类似
  枚举固定最大值为x 的区间有哪些
  在A数组中 假设x 所在位置为  i   ,利用单调栈可以求出 其掌管范围 [L1,R1], 对应的
  在B数组中 假设x 所在位置为  i   ,利用单调栈可以求出 其掌管范围 [L2,R2],
  那么抽出 [L1,i] [i,R1],  [L2,i] [i,R2], 在二维坐标系上就是两个矩阵,求出矩阵面积交就可以了
#include <bits/stdc++.h>
inline long long read(){long long x=0,f=1;char ch=getchar();while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}return x*f;}
using namespace std;
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define MP make_pair
typedef long long LL;
typedef unsigned long long ULL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int  N = 4e5 + 10, M = 1e3, inf = 2e9;

int n,a[N],b[N];
int l[2],r[2],q[2][N],pos[2][N];
LL cal(int x,int p,int i) {
     int ll = l[p], rr = r[p],ok = ll;
     while(ll <= rr) {
        if(q[p][mid] > x) {
            ll = mid + 1;
        } else ok = mid,rr = mid - 1;
    }
  //  cout<<i<<" "<<p<<" "<<ok<<" "<<q[p][ok]<<" "<<x<<endl;
    int mmp1,mmp2;
    mmp1 = max(pos[p][ok-1]+1,pos[p^1][r[p^1]-1]+1);
    mmp2 = i-1;

    if(q[p][ok] == x)
        return 1LL * max(min(pos[p^1][r[p^1]],pos[p][ok]) - mmp1+1,0)
        * max(mmp2 - max(pos[p^1][r[p^1]],pos[p][ok]) + 1,0);
    else return 0;
}
int main() {
    cin >> n;
    for(int i = 1; i <= n; ++i) scanf("%d",&a[i]);
    for(int i = 1; i <= n; ++i) scanf("%d",&b[i]);
    l[0] = l[1] = 1;
    r[0] = r[1] = 0;
    pos[0][0] = pos[1][0] = 0;
    LL ans = 0;
    for(int i = 1; i <= n; ++i) {
        LL ret = 0;
        while(l[0] <= r[0] && a[i] >= q[0][r[0]]) {
            ret += cal(q[0][r[0]],1,i);
            r[0]--;
        }
        q[0][++r[0]] = a[i];pos[0][r[0]] = i;
        while(l[1] <= r[1] && b[i] >= q[1][r[1]]) {
            ret += cal(q[1][r[1]],0,i);
            r[1]--;
        }
        q[1][++r[1]] = b[i];pos[1][r[1]] = i;
        //cout<<"fuck "<<i<<" "  << ret<<endl;
        ans += ret;
    }
    while(l[0] <= r[0]) {
        ans += cal(q[0][r[0]],1,n+1);
        r[0]--;
    }
    cout<<ans<<endl;
    return 0;
}

 


以上是关于51NOD 1962 区间计数 单调栈+二分 / 线段树+扫描线的主要内容,如果未能解决你的问题,请参考以下文章

51nod1962区间计数

51Nod1962 区间计数

51nod 1349 最大值(单调栈)

51nod 1437 迈克步(单调栈)

51nod 1215 数组的宽度&poj 2796 Feel Good(单调栈)

51nod 1423 最大二“货” 单调栈