51NOD算法马拉松 最大值问题 离线预处理+set lower_bound

题目:http://www.51nod.com/contest/problem.html#!problemId=1349

题意:100000个数的序列,有100000次询问,每次问区间最大值大于等于k的区间有多少?

思路:一开始没看到“大于等于”,想了很久也不会,原来看错题了。看错题害死人。

一般询问的问题,如果不能用线段树log(n)求出,那么就离线做。

首先将询问按从大到小排序,再将序列中的每个数排序,注意记录序号。

对于当前询问,每加进一个数,我需要找到它在加进的序列(按大小有序的)上下界,即上下编号high,low.

那么加进这个数的影响就是在【high,low】中选取经过当前id的区间数。所以我用set存储,low_bound查找边界.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#include<algorithm>
using namespace std;
const int N = 1e5+10;
typedef long long ll;

int n,m;
struct query{
    int id;
    int k;
    ll ans;
}q[N],a[N];

int cmp(query a,query b){
    return a.k > b.k;
}
int cmp2(query a,query b){
    return a.id < b.id;
}
struct num1{
    int x;
    bool operator<(const num1& b)const {
        return x<b.x;
    }
};
struct num2{
    int x;
    bool operator<(const num2& b)const {
        return x>b.x;
    }
};

set<num1> s1;
set<num1>::iterator it1;
set<num2> s2;
set<num2>::iterator it2;
void solve(){
    s1.clear(); s2.clear();
    int p1=1,p2=1;
    ll ans = (ll)n*(n-1)/2 + n;
    ll co = 0;
    while(p2<=m){
        int wt = q[p2].k;
        while(a[p1].k>=wt && p1<=n){
            int idt = a[p1].id;
            num1 tmp1; tmp1.x = idt;
            num2 tmp2; tmp2.x = idt;
            s1.insert(tmp1);
            s2.insert(tmp2);
            it1 = s1.upper_bound(tmp1);
            it2 = s2.upper_bound(tmp2);

            int high,low;
            if(it1==s1.end()) high=n;
            else high = (*it1).x-1;

            if(it2==s2.end()) low=1;
            else low = (*it2).x+1;
            co += (ll)(idt-low)*(high-idt) + (high-low+1);

            p1++;
        }
        q[p2].ans = co;
        p2++;
    }
}

int main(){
    cin >> n ;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i].k);
        a[i].id = i;
    }
    cin >> m;
    for(int i=1;i<=m;i++){
        scanf("%d",&q[i].k);
        q[i].id = i;
    }
    sort(a+1,a+1+n,cmp);
    sort(q+1,q+1+m,cmp);
    solve();
    sort(q+1,q+1+m,cmp2);
    for(int i=1;i<=m;i++)
        printf("%lld\n",q[i].ans);
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-06 20:09:57

51NOD算法马拉松 最大值问题 离线预处理+set lower_bound的相关文章

51Nod 算法马拉松21(迎新年)

这次打算法马拉松是在星期五的晚上,发挥还算正常(废话,剩下的题都不会= =). 讲讲比赛经过吧. 8:00准时发题,拿到之后第一时间开始读. A配对,看上去像是二分图最大权匹配,一看范围吓傻了,先跳过读后面的题. B完全二叉树的方差,大概看了一遍,好神的样子,跳过. C多项式?好吧没学过FFT和NTT的我肯定不会,跳跳跳. D最大值,哎呦这函数什么破玩意儿,看不懂,跳跳跳. E B君的射击,卧槽毕克大人您出题就算了出这么一道码农题是要闹那样,跳跳跳. F那些年,我们一起讲的故事,卧槽这特么简直就

随便玩玩系列之一:SPOJ-RNG+51nod 算法马拉松17F+51nod 1034 骨牌覆盖v3

先说说前面的SPOJ-RNG吧,题意就是给n个数,x1,x2,...,xn 每次可以生成[-x1,x1]范围的浮点数,把n次这种操作生成的数之和加起来,为s,求s在[A,B]内的概率 连续形的概率,想象为一个n维长方体,有两个平面与这个几何图形相割,于是就变成了求面(体)积问题,一般要去重,n维区域系数:s^n/n!,至于区间问题,直接前缀之差搞定 然后就是悲催的算法马拉松17F题了...其实是道好题来的,只是出题人不知世界上还有这题,然后某大牛把思路理清后把答案直接搬了过来 经典的1*2骨牌覆

51Nod 算法马拉松15 记一次悲壮而又开心的骗分比赛

OwO 故事的起源大概是zcg前天发现51Nod晚上有场马拉松,然后他就很开心的过去打了 神奇的故事就开始了: 晚上的时候我当时貌似正在写线段树?然后看见zcg一脸激动告诉我第一题有九个点直接输出B就可以A.. 然后之后zcg以奇怪的二分方式发现了如何A掉第一题的第十个点(我记得貌似是什么第5000个数等于511? OwO 就这样没有任何思考含量全凭骗分黑科技过掉了第一题 OwO 然后zcg打开了第二题,发现第二题样例有点问题,然后就发了个帖子,直接去看第三题了 我去瞅了一眼,发现这不是gcd

51nod算法马拉松14

这次太丢人了只搞出来了A到D,那就将就写一写A到D... A 棋盘问题 脑筋急转弯题,不难发现每一次两个人只能染白奇数个格子,所以数数有奇数还是偶数个白格子就行了. #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i

51nod算法马拉松 contest7

A题 链接:http://www.51nod.com/contest/problem.html#!problemId=1417 推荐链接:http://blog.csdn.net/a837199685/article/details/45009337 设美女取得正面概率是p,反面就是(1-p),就是美女取一正一反和一反一正的概率相同,然后推出公式y=((a+b)/2+b)/(2*(a+b)); 1 #include<iostream> 2 #include<cstdio> 3 #i

51Nod 算法马拉松23 开黑记

惨啊--虽然开了半天黑,但是还是被dalao们踩了-- 第二次开黑,还是被卡在rank20了,我好菜啊--= = 写一写比赛经过吧-- 看到题之后习惯性都打开,A~D看上去似乎并没有什么思路,F应该是道数论题,看了E感觉有点意思,一看数据范围,咦怎么只有$50000$,再仔细看一看式子,手动分情况讨论之后得到一个结论-- 这题是水的线段树维护莫队啊= = 然后就开始码码码,由于一些脑残错误调了一会儿,然后就得到了这样的结果: 我坚信自己莫队的复杂度没错,然后就开始各种王逸松卡常,使用的卡常技巧包

51nod 算法马拉松4

http://www.51nod.com/contest/problemList.html#!contestId=9 D 装盒子 拓扑排序?

51nod算法马拉松15

智力彻底没有了...看来再也拿不到奖金了QAQ... A B君的游戏 因为数据是9B1L,所以我们可以hash试一下数据... #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) using n

51nod 算法马拉松35 E

有这样一段两两求最大公约数的程序CoGcd, int Gcd(int x, int y){ if(y == 0)return x; return Gcd(y, x % y); } void CoGcd(int m){ for(int i = 1; i <= m; i++) for(int j = 1; j <= m; j++) Gcd(i, j); } 给出m的值,进行t次询问,每次询问包含一对xi,yi.针对每次询问,输出整个程序执行过程当中,Gcd(xi, yi)被执行了多少次. 例如:\