[线段树]JZOJ 5812

Posted mastervan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[线段树]JZOJ 5812相关的知识,希望对你有一定的参考价值。

Description

每一个机房中总有一个红太阳。有一天,AmberFrame 来到机房,发现桌上有不知道哪个蒟蒻放上的问 题: 有一个 n 个数的序列,一开始所有的数都是 0,每次可以将一个区间 [l, r](l ≤ r) 内的数 +1,求到达最 终状态的最少操作次数。 AmberFrame 非常强,自然不会把时间花在这种水题上。因此他就把任务交给了你,如果不会做的话,他 可能就会觉得你就是那个放问题的蒟蒻了而把你批判一番了。 
 

Input

第一行包含一个正整数 n,表示序列的长度。
第二行包含 n 个非负整数 a1, a2, ..., an,表示最终的状态。

Output

输出的第一行是一个正整数 m,表示最少的操作次数。 接下来 m 行每行两个正整数 li , ri,表示一次操作。你需要保证 1 ≤ li ≤ ri ≤ n。 保证最少次数 m ≤ 10^5,输出可以以任意顺序输出。 
 

Sample Input

6
2 3 3 3 3 3

Sample Output

3
1 6
1 6
2 6
 

Data Constraint

技术分享图片
 

Hint

下发样例中第 i 个样例与第 i 组数据范围相符。
对于样例 1,第一个数被加了两次,其他每个数都被加了三次,显然满足条件。

分析

这题我TMD想复杂了

其实只用线段树记录区间最小值下标,然后分治一波就行,显然每次ans累加上最小值min减当前区间已减量delta

比赛时写了一波O3 inline register等卡时操作(并没有什么作用)

技术分享图片
#pragma GCC optimize(3)
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <queue>
#define l(x) t[x].l
#define r(x) t[x].r
#define m(x) t[x].mn
#define s(x) t[x].pos
using namespace std;
const int N=1e5+1;
struct Node {
    int l,r,mn,pos;
}t[4*N];
struct Adep {
    int l,r,dat;
};
int rt=1;
int a[N];
int ansl[N],ansr[N],cnt;
int n;

inline Adep In(int x,int y,int z) {
    Adep a;a.l=x;a.r=y;a.dat=z;
    return a;
}
inline void Build(int x,int l,int r) {
    l(x)=l;r(x)=r;
    if (l==r) {
        m(x)=a[l];
        s(x)=l;
        return;
    }
    int mid=l+r>>1;
    Build(x*2,l,mid);Build(x*2+1,mid+1,r);
    m(x)=m(x*2);s(x)=s(x*2);
    if (m(x)>m(x*2+1)) m(x)=m(x*2+1),s(x)=s(x*2+1);
}

inline int Query(int x,int l,int r) {
    if (l>r(x)||r<l(x)) return 0;
    if (l<=l(x)&&r(x)<=r) return s(x);
    int mid=l(x)+r(x)>>1,ans=0,val=2147483647;
    if (l<=mid) ans=Query(x*2,l,r),val=a[ans];
    if (mid<r) {
        int d=Query(x*2+1,l,r);
        if (val>a[d]) val=a[d],ans=d;
    }
    return ans;
}

inline void Solve() {
    queue <Adep> q;
    while (!q.empty()) q.pop();
    q.push(In(1,n,0));
    while (!q.empty()) {
        Adep d=q.front();q.pop();
        int l=d.l,r=d.r,dt=d.dat;
        int o=Query(rt,l,r),m=a[o],p=0;
        m-=dt;
        while (m) {
            ansl[++cnt]=l;ansr[cnt]=r;
            m--;p++;
        }
        if (l<=o-1) q.push(In(l,o-1,dt+p));
        if (o+1<=r) q.push(In(o+1,r,dt+p));
    }
}

int main() {
    freopen("range.in","r",stdin);
    freopen("range.out","w",stdout);
    scanf("%d",&n);
    for (register int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (register int i=1;i<=4*n;i++) t[i].mn=2147483647;
    a[0]=2147483647;
    Build(rt,1,n);
    Solve();
    printf("%d
",cnt);
    for (register int i=1;i<=cnt;i++) printf("%d %d
",ansl[i],ansr[i]);
    fclose(stdin);fclose(stdout);
}
View Code

 



以上是关于[线段树]JZOJ 5812的主要内容,如果未能解决你的问题,请参考以下文章

[线段树]JZOJ 1214 项链工厂

魔性の分块 | | jzoj1243 | | 线段树の暴力

[线段树] Jzoj P4231 寻找神格

[扫描线][倍增][dfs序][线段树] Jzoj P6276 树

JZOJ 5750. 青青草原播种计划 (小性质+线段树)

JZOJ 5750. 青青草原播种计划 (小性质+线段树)