CF526F Pudding Monsters 線段樹+單調棧
阿新 • • 發佈:2020-07-11
剛開始想出了一個分治做法,但是比較麻煩,需要分 4 中情況討論.
後來偷看了一眼標籤發現是線段樹,然後就想出了這個線段樹做法.
考慮序列以 $r$ 為右端點的答案,有 $\sum_{l=1}^{i} max(l,i)-min(l,i)=i-l$.
其中這個條件可以寫成 $max(l,i)-min(l,i)+l=i$.
然後特別注意任何時候都滿足不等式:$r-l \leqslant max(l,r)-min(l,r)$
考慮通過單調棧維護最大/最小值的過程中用線段樹維護以 $i$ 為右端點,$j$ 為左端點的答案.
1. 假如新元素 $i$,則 $i$ 的貢獻就是 $a[i]-a[i]+i=i$.
2. 維護最大值的單調棧要彈棧,則說明一段連續區間的最大值由原來的 $max.top() \Rightarrow a[i]$,則做區間加法.
3. 維護最小值時和最大值同理.
這樣我們只需用線段樹做區間加法就可以求出最小值個數,然後根據不等式:$r-l \leqslant max(l,r)-min(l,r)$ 可知最小值一定為 $i$,加上個數即可.
code:
#include <stack> #include <cstdio> #include <cstring> #include <algorithm> #define N 300009 #define ll long long #define lson now<<1 #define rson now<<1|1 #define inf 1000000000 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,a[N]; stack<int>mi,ma; struct data { int x,y; data(int o=inf,int z=0) { x=o,y=z; } data operator+(const data b) const { data c; c.x=min(x,b.x); if(x==c.x) c.y+=y; if(b.x==c.x) c.y+=b.y; return c; } }s[N<<2]; int lazy[N<<2]; void mark(int now,int v) { lazy[now]+=v; s[now].x+=v; } void pushdown(int now) { if(lazy[now]) { mark(lson,lazy[now]); mark(rson,lazy[now]); lazy[now]=0; } } void modify(int l,int r,int now,int p,int v) { if(l==r) { s[now].x=v; s[now].y=1; return; } pushdown(now); int mid=(l+r)>>1; if(p<=mid) modify(l,mid,lson,p,v); else modify(mid+1,r,rson,p,v); s[now]=s[lson]+s[rson]; } void update(int l,int r,int now,int L,int R,int v) { if(l>=L&&r<=R) { mark(now,v); return; } pushdown(now); int mid=(l+r)>>1; if(L<=mid) update(l,mid,lson,L,R,v); if(R>mid) update(mid+1,r,rson,L,R,v); s[now]=s[lson]+s[rson]; } data query(int l,int r,int now,int L,int R) { if(l>=L&&r<=R) { return s[now]; } pushdown(now); int mid=(l+r)>>1; if(L<=mid&&R>mid) { return query(l,mid,lson,L,R)+query(mid+1,r,rson,L,R); } else if(L<=mid) return query(l,mid,lson,L,R); else return query(mid+1,r,rson,L,R); } int pmi[N],pma[N]; int main() { // setIO("input"); scanf("%d",&n); int x,y,z; for(int i=1;i<=n;++i) { scanf("%d%d",&x,&y); a[y]=x; } ll ans=0; for(int i=1;i<=n;++i) { modify(1,n,1,i,i); z=i-1; while(!mi.empty()&&a[i]<a[mi.top()]) { update(1,n,1,pmi[mi.top()],z,a[mi.top()]-a[i]); z=mi.top()-1; mi.pop(); } z=i-1; while(!ma.empty()&&a[i]>a[ma.top()]) { update(1,n,1,pma[ma.top()],z,a[i]-a[ma.top()]); z=ma.top()-1; ma.pop(); } pmi[i]=mi.empty()?1:mi.top()+1; pma[i]=ma.empty()?1:ma.top()+1; mi.push(i); ma.push(i); ans+=s[1].y; } printf("%lld\n",ans); return 0; }