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.
1≤N≤3.5×1051≤Ai,Bi≤N
样例解释:
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 区间计数 单调栈+二分 / 线段树+扫描线的主要内容,如果未能解决你的问题,请参考以下文章