Problem
Solution
发现有些题目把情况分类讨论就可以使题目好处理很多。
注意到每行每列都只有一个怪物,那么我们可以将其转化到一维的情况,则可以得到一个排列,那么问题就变为了,统计有多少个子区间 [ L , R ] [L,R] [L,R]满足 m x − m n = R − L mx-mn=R-L mx−mn=R−L。好像很不好处理…
考虑跨越中点的区间,分类讨论一下 m x mx mx和 m n mn mn的分布:
若 m n , m x mn,mx mn,mx在左边,查 m x [ i ] − m n [ i ] = p − i mx[i]-mn[i]=p-i mx[i]−mn[i]=p−i,则 p = m x [ i ] − m n [ i ] + i p=mx[i]-mn[i]+i p=mx[i]−mn[i]+i
若在都在右边,查 p = − m x [ i ] + m n [ i ] + i p=-mx[i]+mn[i]+i p=−mx[i]+mn[i]+i
再考虑不在同一边的情况,比如 m n mn mn在左, m x mx mx在右,需要询问右边是否存在一个位置 p p p,满足 m x [ p ] − m n [ i ] = p − i mx[p]-mn[i]=p-i mx[p]−mn[i]=p−i,即 m n [ i ] − i = m x [ p ] − p mn[i]-i=mx[p]-p mn[i]−i=mx[p]−p
m x mx mx在左, m n mn mn在右,要询问左边是否存在一个位置 p p p,满足 m x [ p ] − m n [ i ] = i − p mx[p]-mn[i]=i-p mx[p]−mn[i]=i−p,即 − i − m n [ i ] = − m x [ p ] − p -i-mn[i]=-mx[p]-p −i−mn[i]=−mx[p]−p
但要注意,分类讨论之后要注意判断左右两边的 m n mn mn和 m x mx mx是否满足相应的大小关系,而且对于mx和mn不在同一边时,注意到两边的最值具有单调性,所以合法的区间应该是一段连续的区间,可以用队列实现。
T ( n ) = 2 T ( n 2 ) + O ( n ) , T ( n ) = O ( n log n ) T(n)=2T(\frac n 2)+O(n),T(n)=O(n\log n) T(n)=2T(2n)+O(n),T(n)=O(nlogn)
Code
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=300010,N=300005;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
struct tong{
int a[maxn<<1];
void insert(int x){++a[x];}
void erase(int x){--a[x];}
int query(int x){return a[x];}
}t;
int n,x,a[maxn],mn[maxn],mx[maxn];
ll ans;
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
void solve(int l,int r)
{
if(l==r) return ;
int m=(l+r)>>1,p,L,R;
mx[m]=mn[m]=a[m];mx[m+1]=mn[m+1]=a[m+1];
for(int i=m-1;i>=l;i--){mx[i]=max(mx[i+1],a[i]);mn[i]=min(mn[i+1],a[i]);}
for(int i=m+2;i<=r;i++){mx[i]=max(mx[i-1],a[i]);mn[i]=min(mn[i-1],a[i]);}
L=R=m+1;
for(int i=m;i>=l;i--)//左小右大
{
p=mx[i]-mn[i]+i;
if(m<p&&p<=r&&mn[p]>mn[i]&&mx[p]<mx[i]) ++ans;
while(R<=r&&mn[i]<mn[R]) t.insert(mx[R]-R+N),++R;
while(L<R&&mx[i]>mx[L]) t.erase(mx[L]-L+N),++L;
ans+=t.query(mn[i]-i+N);
}
while(L<R) t.erase(mx[L]-L+N),++L;
L=R=m;
for(int i=m+1;i<=r;i++)//左大右小
{
p=-mx[i]+mn[i]+i;
if(l<=p&&p<=m&&mn[p]>mn[i]&&mx[p]<mx[i]) ++ans;
while(l<=L&&mn[i]<mn[L]) t.insert(mx[L]+L),--L;
while(L<R&&mx[i]>mx[R]) t.erase(mx[R]+R),--R;
ans+=t.query(mn[i]+i);
}
while(L<R) t.erase(mx[R]+R),--R;
solve(l,m);solve(m+1,r);
}
int main()
{
read(n);ans=n;
for(int i=1;i<=n;i++){read(x);read(a[x]);}
solve(1,n);
printf("%lld\n",ans);
return 0;
}