首页 > 代码库 > 北邮校赛 F. Gabriel's Pocket Money(树状数组)

北邮校赛 F. Gabriel's Pocket Money(树状数组)

F. Gabriel‘s Pocket Money 2017- BUPT Collegiate Programming Contest - sync

时间限制 2000 ms 内存限制 65536 KB

题目描述

技术分享
For centuries, Heaven has required its young angels to live and study among humans in order to become full-fledged angels. This is no different for top-of-her-class Gabriel White Tenma, who believes it is her mission to be a great angel who will bring happiness to mankind.
However, Gabriel grows addicted to video games on Earth and eventually becomes a hikikomori. What‘s worse, her grades in school becomes erratic, which directly determines how much pocket money she could get from Heaven. Every week Gabriel needs to report her recent grade in school, and Heaven will give her some money based on her reports. In each report Gabriel is asked to offer two grades, the grade she get this week and a grade she has ever got before this week to show she is improved or at least not going backwards, like "I once got 59 points, and I get 61 points this week. So I‘m improved!" or "I once got 59 points, and this week I get 59 points again. So I‘m not going backwards!". Then Heaven will give her as much pocket money as her former grade points she reported (In both cases, she can get 59 dollars. What a hardworking angel!). If she can‘t offer such report, no pocket money would be offered this week. For example, the first week (she has only one grade).
Gabriel knows how to maximize the pocket money she get from heaven. Giving you Gabriel‘s transcript of this semester in order, can you figure out how much pocket money she can get in total?

输入格式

Input contains multiple test cases.
For each test case:

  • The first line contains an integers n(1n106), indicating the number of weeks;
  • The second line contains n integers a1,a2,...,an(0ai106).

 

输出格式

For each test case, output a number in a single line, indicating the total pocket money Gabriel can get. You should let answer modulo 19260817 before printing it.

输入样例

3
1 2 3
5
3 5 1 2 4

输出样例

3
7
【题意】给你一个数组,然后对于每个数,找到左边小于等于它的最大的那个数,然后依次累加起来。
【分析】数据小的话,可以O(N*N)来做,可是 N<1e6,那就只能树状数组了,对于每一个数,向上lowbit更新Lazy标记,Lazy标记的是
到目前为止这个数左边小于等于它的最大的数,那么查询的时候只需要向下lowbit查询取最大值就行了,复杂度NlogN。
#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define met(a,b) memset(a,b,sizeof a)
#define inf 10000000
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int N = 1e6+5;
const double eps = 1e-8;
int n,sum[N],m,cnt,k;
int lazy[N],a[N];
void update(int x,int num){
    for(int i=x;i<N;i+=i&(-i)){
        lazy[i]=max(lazy[i],num);
    }
}
int query(int x){
    int ret=0;
    for(int i=x;i>=1;i-=i&(-i)){
        ret=max(ret,lazy[i]);
    }
    return ret==0?ret:ret-1;
}
int main() {
    int T,x,y,xx,yy;
    while(~scanf("%d",&n)){
        met(lazy,0);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            a[i]++;
        }
        ll ans=0;
        for(int i=1;i<=n;i++){
            int s=query(a[i]);
            ans=(ans+s)%19260817;
            update(a[i],a[i]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

北邮校赛 F. Gabriel's Pocket Money(树状数组)