[线段树]JZOJ 5812
分析
这题我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); }
在日渐沉没的世界里,我发现了你。