zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    关于vue2.x使用axios以及http-proxy-middleware代理处理跨域的问题
    vue-resource的使用
    从头开始开发一个vue幻灯片组件
    图与例解读Async/Await
    浅谈web缓存
    APICloud框架——总结一下最近开发APP遇到的一些问题 (三)
    编写现代 CSS 代码的 20 个建议
    仿微信联系人列表滑动字母索引
    初来乍到,向各位大牛虚心学习
    转发80端口的脚本
  • 原文地址:https://www.cnblogs.com/zxhl/p/7596793.html
Copyright © 2011-2022 走看看