单调栈+按位置建树,数据结构就是解决问题时用的容器

牛牛与牛妹的RMQ

https://ac.nowcoder.com/acm/contest/9982/A

单调栈 + 按位置建树

先求出每个点作为最大值的区间范围(用单调栈优化)
经过证明单调栈放下标更好,以后一般都用下标
单调栈:扔一次删一次,所以复杂度为O(n)
数据结构就是解决问题时用的容器
并查集也是容器

按位置建树
求某个点左边(或右边)有多少个可选的点
可以用ask求

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define low(x) x&(-x) 
int const N=1e5+7;
int INF=0x3f3f3f3f;
int n;
struct L{
    int a,l,r;
}b[N];
stack<int>s;
void pan(){
    b[0].a=INF;
    s.push(0);
    s.push(1);
    b[1].l=1;
    for(int i=2;i<=n;++i){
        while( b[i].a >= b[ s.top() ].a&&!s.empty() ) s.pop();
        b[i].l=s.top()+1;
        s.push(i);
    }
    if(!s.empty()) s.pop();
    b[n+1].a=INF;
    s.push(n+1);
    s.push(n);
    b[n].r=n;
    for(int i=n-1;i>=1;--i){
        while( b[i].a >= b[ s.top() ].a&&!s.empty() ) s.pop();
        b[i].r=s.top()-1;
        s.push(i);
    }
}
int m;
ll c[N],p[N];
void add(int i,int w){   //位置和值要分清楚 
    for(;i<=n;i+=low(i)){
        c[i]+=w;
    }
}
ll ask(int x){
    ll res=0;
    for(;x;x-=low(x)){
        res+=c[x];
    }
    return res;
}
map<ll,ll>mp; //
ll calc(int x){ //计算 MRQ(l,r)=x 的方案数 
    ll ls= ask(x)-ask(b[x].l-1) ; //ls表示以x号点为区间最大值 左边(包括x)可选的点数
    ll rs=ask(b[x].r)-ask(x-1) ;
    ll res=ls*rs*2;
    if(ask(x)-ask(x-1)==1) res--;   //如果j这个地方有点则-1
    return res;
}
ll gcd(ll a,ll b){
    return b==0?a:gcd(b,a%b);
}
int main(){
    cin >> n;
    for(int i=1;i<=n;++i){
        cin >> b[i].a;
    }
    pan();
    cin >> m;
    int k;
    while(m--){
        cin >> k;
        for(int i=1;i<=k;++i){
            cin >> p[i];
            add(p[i],1);
        }    
        ll sum=(ll)k*k;    //
        for(int i=1;i<=k;++i){
            mp[b[p[i]].a]=calc(p[i]);   // mp[j]表示以z值为区间最大值的方案数 
            /*还有一种情况:
            样例:3 
                  1 5 2
                  1
                  2 1 3
            此时的2号点不在可选范围,但 RMQ(1,3)=5
            以下就是去掉此种情况的代码 
            */ 
            int l=b[p[i]].l -1;    //左边界的左边l一定比b[p[i]].a大,所以其有可能成为区间最大值
            while(l>=1&&mp.find(b[l].a)==mp.end()){
                mp[b[l].a]=calc(l);
                l=b[l].l -1;
            }
            int r=b[p[i]].r +1;
            while(r<=n&&mp.find(b[r].a)==mp.end()){
                mp[b[r].a]=calc(r);
                r=b[r].r +1;
            }
        }
        for(map<ll,ll>::iterator it=mp.begin();it!=mp.end();it++){
            if((*it).second!=0) {
                ll z=gcd(sum,it->second);
                cout << (*it).first << " " << (*it).second/z << "/" << sum/z << "\n";
            }
        }
        mp.clear();
        for(int i=1;i<=k;++i){
            add(p[i],-1);
        }
    }
    return 0;
}
线段树和数状数组经典例题 文章被收录于专栏

线段树和数状数组经典例题

全部评论

相关推荐

点赞 评论 收藏
分享
03-08 18:11
门头沟学院 Java
Java抽象小篮子:海投就完事了,简历没什么问题,最大问题是学历
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
正在热议
更多
# 春招至今,你的战绩如何? #
11367次浏览 96人参与
# 你的实习产出是真实的还是包装的? #
2013次浏览 42人参与
# MiniMax求职进展汇总 #
24198次浏览 310人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
7684次浏览 43人参与
# 简历第一个项目做什么 #
31788次浏览 343人参与
# 重来一次,我还会选择这个专业吗 #
433634次浏览 3926人参与
# 米连集团26产品管培生项目 #
6102次浏览 216人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
187253次浏览 1122人参与
# 牛客AI文生图 #
21456次浏览 238人参与
# 不考虑薪资和职业,你最想做什么工作呢? #
152506次浏览 888人参与
# 研究所笔面经互助 #
118983次浏览 577人参与
# 简历中的项目经历要怎么写? #
310452次浏览 4223人参与
# AI时代,哪些岗位最容易被淘汰 #
63971次浏览 832人参与
# 面试紧张时你会有什么表现? #
30527次浏览 188人参与
# 你今年的平均薪资是多少? #
213187次浏览 1039人参与
# 你怎么看待AI面试 #
180244次浏览 1261人参与
# 高学历就一定能找到好工作吗? #
64345次浏览 620人参与
# 你最满意的offer薪资是哪家公司? #
76600次浏览 374人参与
# 我的求职精神状态 #
448210次浏览 3129人参与
# 正在春招的你,也参与了去年秋招吗? #
363606次浏览 2638人参与
# 腾讯音乐求职进展汇总 #
160707次浏览 1112人参与
# 校招笔试 #
471441次浏览 2964人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务