CF526F Pudding Monsters

Solution

如果一个 \(k*k\) 的矩阵里放满了 \(k\) 个数,容易发现横坐标和纵坐标都是连续的,我们需要利用好这个性质,那么不妨按横坐标排序,之后只有相连的几个点会造成贡献。对于一个区间 \([l,r]\),如果它是合法的,当且仅当区间长度等于值域长度(由于合法时值域一定是连续的),即

\[r-l+1=\max \limits_{l\leq i\leq r} \{y_i\}-\min \limits_{l\leq i\leq r} \{y_i\}+1 \]

对于一个确定的 \(r\) 只需要统计方程

\[\max \limits_{l\leq i\leq r} \{y_i\}-\min \limits_{l\leq i\leq r} \{y_i\}-r+l=0 \]

成立的个数。可以用线段树对每一个位置维护这个值。考虑到没有重复的数,值域长度一定大于等于区间长度,那么上式左边会恒大于等于 0,而 \(r\) 这个单独的位置一定有一个合法解,即会出现 0,所以只需统计区间最小值(0)出现次数就行了。

对于线段树的维护,考虑增量法。当从 \(r\) 转移到 \(r+1\)\(r\) 会加 1,那么 \([1,r]\) 的所有位置的数减 1。对于 \(min\)\(max\) 用单调栈维护一下,弹栈时对数列更新一下最大值最小值信息即可。

考虑到每次弹栈入栈会 \(modify\) 一次,所以复杂度 \(O(n\log n)\)

#include<stdio.h>
#define lid id<<1
#define rid id<<1|1
#define N 300007

inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

int s[N<<2],num[N<<2],tag[N<<2];

void build(int id,int lf,int rf){
    s[id]=1;
    if(lf==rf) return ;
    int mid=(lf+rf)>>1;
    build(lid,lf,mid);
    build(rid,mid+1,rf);
    s[id]=s[lid]+s[rid];
}

inline int min(int x,int y){return x<y? x:y;}
void push(int id,int v){num[id]+=v,tag[id]+=v;}
void pushdown(int id){push(lid,tag[id]),push(rid,tag[id]),tag[id]=0;}
void modify(int id,int lf,int rf,int l,int r,int val){
    if(l<=lf&&rf<=r) push(id,val);
    else{
        int mid=(lf+rf)>>1;
        if(tag[id]) pushdown(id);
        if(l<=mid) modify(lid,lf,mid,l,r,val);
        if(r>mid) modify(rid,mid+1,rf,l,r,val);
        num[id]=min(num[lid],num[rid]);
        s[id]=(num[id]==num[lid]? s[lid]:0)+(num[id]==num[rid]? s[rid]:0);
    }
}

int n,ma[N],mi[N],t1=0,t2=0,a[N];
int main(){
    n=read();
    for(int i=1;i<=n;i++) a[read()]=read();
    build(1,1,n);
    long long ans=0;
    for(int i=1;i<=n;i++){
        modify(1,1,n,1,i,-1);
        while(t1&&a[ma[t1]]<a[i])
            modify(1,1,n,ma[t1-1]+1,ma[t1],a[i]-a[ma[t1]]),t1--;
        while(t2&&a[mi[t2]]>a[i])
            modify(1,1,n,mi[t2-1]+1,mi[t2],a[mi[t2]]-a[i]),t2--;
        ma[++t1]=mi[++t2]=i;
        ans+=1LL*s[1];
    }
    printf("%lld",ans);
}
posted @ 2020-12-18 22:01  Kreap  阅读(95)  评论(0编辑  收藏  举报