CF526F Pudding Monsters 线段树+单调栈
刚开始想出了一个分治做法,但是比较麻烦,需要分 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; }