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
",ans);    
    return 0;   
}

  

原文地址:https://www.cnblogs.com/guangheli/p/13282321.html