题解[51nod1555] 布丁怪

半城伤御伤魂 提交于 2019-12-04 08:30:34

题解[51nod1555] 布丁怪

题面

解析

本文参考这位dalao的题解

首先有一个巧妙的转换,

开一个数组记录每个横坐标的纵坐标,

简单来说就是对于点(x,y),令a[x]=y.

于是问题就变成了求满足区间最大值与最小值的差恰好等于区间长度的区间数.

于是可以考虑分治不要问我怎么想到的

设当前区间为l,r,中点为mid.

mx[i]=i~mid的最大值(l<=mid),mid+1到i的最大值(i>mid)

mn[i]同理.

分情况讨论:

1.区间最大值和最小值都在左边.

设右端点为j,这时候j要满足mn[j+1]<mn[i]或mx[j+1]>mx[i],否则j+1也在mn~mx这个范围里面,j肯定不能是端点.

然后再看j-i是否等于mx[i]-mn[i].

2.最大值在左边,最小值在右边.

因为mx和mn都是单调的,所以拿两个指针L和R维护满足要求的右端点,

然后设右端点为j,则mx[i]-mn[j]=j-i,

即mx[i]+i=mn[j]+j,

开个桶维护一下就行了.

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
using namespace std;

inline int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return f*sum;
}

const int N=1000005;
int n,a[N];ll ans,cnt[N];
int mx[N],mn[N];

inline void work(int l,int r,int m){
    mx[m]=mn[m]=a[m];
    for(int i=m-1;i>=l;i--){
        mx[i]=max(mx[i+1],a[i]);
        mn[i]=min(mn[i+1],a[i]);
    }
    mx[m+1]=mn[m+1]=a[m+1];
    for(int i=m+2;i<=r;i++){
        mx[i]=max(mx[i-1],a[i]);
        mn[i]=min(mn[i-1],a[i]);
    }
    int L=m+1,R=m,j=m;
    for(int i=m;i>=l;i--){
        while(j<r&&mx[j+1]<mx[i]&&mn[j+1]>mn[i]) j++;
        if(mx[i]-mn[i]==j-i&&j>m) ans++;
        while(R<r&&mx[R+1]<mx[i]) R++,cnt[R+mn[R]]++;
        while(L<=r&&mn[L]>mn[i]) cnt[L+mn[L]]--,L++;
        if(L<=R) ans+=cnt[i+mx[i]];
    }
    while(L<=r) cnt[L+mn[L]]--,L++;
    while(R<r) R++,cnt[R+mn[R]]++;
}

inline void solve(int l,int r){
    if(l==r){ans++;return ;}
    int mid=(l+r)>>1;
    solve(l,mid);solve(mid+1,r);
    work(l,r,mid);
    reverse(a+l,a+r+1);
    if((r-l+1)%2) mid--;
    work(l,r,mid);
    reverse(a+l,a+r+1);
}

signed main(){
    n=read();
    for(int i=1;i<=n;i++)
    {int x=read();a[x]=read();}
    solve(1,n); 
    printf("%lld\n",ans);
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!