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

牛牛与牛妹的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-17 23:54
黑龙江大学 Java
来个白菜也好啊qaq:可以的,大厂有的缺打手
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
正在热议
更多
# 春招至今,你的战绩如何? #
13285次浏览 128人参与
# AI面会问哪些问题? #
779次浏览 18人参与
# 巨人网络春招 #
11453次浏览 224人参与
# 你的实习产出是真实的还是包装的? #
2385次浏览 47人参与
# AI时代,哪个岗位还有“活路” #
2443次浏览 47人参与
# 长得好看会提高面试通过率吗? #
2207次浏览 39人参与
# MiniMax求职进展汇总 #
24557次浏览 313人参与
# 你做过最难的笔试是哪家公司 #
980次浏览 18人参与
# HR最不可信的一句话是__ #
874次浏览 31人参与
# 沪漂/北漂你觉得哪个更苦? #
859次浏览 28人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
7883次浏览 43人参与
# XX请雇我工作 #
51096次浏览 171人参与
# 简历中的项目经历要怎么写? #
310725次浏览 4245人参与
# 简历第一个项目做什么 #
31944次浏览 353人参与
# 不考虑薪资和职业,你最想做什么工作呢? #
152716次浏览 888人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
187473次浏览 1123人参与
# AI时代,哪些岗位最容易被淘汰 #
64356次浏览 855人参与
# 如果重来一次你还会读研吗 #
229933次浏览 2011人参与
# 正在春招的你,也参与了去年秋招吗? #
364010次浏览 2640人参与
# 腾讯音乐求职进展汇总 #
160790次浏览 1114人参与
# 你怎么看待AI面试 #
180504次浏览 1286人参与
# 投格力的你,拿到offer了吗? #
178015次浏览 889人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务