1. 程式人生 > >[線段樹]JZOJ 5812

[線段樹]JZOJ 5812

ttl bvs big jpeg 其他 emf ldp aic bim

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\n",cnt); for (register int i=1;i<=cnt;i++) printf("%d %d\n",ansl[i],ansr[i]); fclose(stdin);fclose(stdout); }
View Code

[線段樹]JZOJ 5812