分治
分治的方法很巧妙,就是写起来有一点小恶心
先放CF题解:http://codeforces.com/blog/entry/17281
题意就是问有多少连续区间满足区间内数字连续,这类序列计数一般考虑分治。
一个分治区间[l,r],考虑怎么统计过mid的答案。
暴力枚举左端点,然而右端点并不单调,不太好维护,考虑其他方法。
出现上述情况,当且仅当已经有合法的跨mid的区间[a,b],然后b右边下一个元素可以补充在连续区间的左右两侧,也就是区间可以扩张。主要原因是最大最小值会变化。
那就大力分类讨论最大最小值。最大最小值同侧的,单调枚举即可。对于异侧的,除了考虑到b-a=mx[b]-mi[a]或b-a=mx[a]-mi[b]之外,还有的限制是区间内不能有超过极值的值,这个限制导致随着左端点左移,右边的贡献区间的两个端点都是单调右移的,维护一下即可。
#include<cstdio>
#include<algorithm>
#define N 300005
using namespace std;
namespace runzhe2000
{
typedef long long ll;
const int INF = 1<<29;
int read()
{
int r = 0; char c = getchar();
for(; c < '0' || c > '9'; c = getchar());
for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());
return r;
}
void mswap(int &a, int &b){int t = a; a = b; b = t;}
int n, a[N], mi[N], mx[N], sum[N<<1], sumR[N<<1], sumL[N<<1];
ll ans;
void dc(int l, int r)
{
if(l == r) {ans++; return;} int mid = (l+r)>>1;
mi[mid] = mx[mid] = a[mid]; for(int i = mid-1; i >= l; i--) mi[i] = min(a[i], mi[i+1]), mx[i] = max(a[i], mx[i+1]);
mi[mid+1] = mx[mid+1] = a[mid+1]; for(int i = mid+2; i <= r; i++) mi[i] = min(a[i], mi[i-1]), mx[i] = max(a[i], mx[i-1]);
// min & max in L
int curl = mid, curr = mid;
for(; curl >= l; curl--)
{
for(; curr < r && mi[curl] < a[curr+1] && a[curr+1] < mx[curl]; curr++);
if(curl < mid && curr > mid && curr - curl == mx[curl] - mi[curl]) ans++;
}
// min & max in R
curl = mid+1, curr = mid+1;
for(; curr <= r; curr++)
{
for(; curl > l && mi[curr] < a[curl-1] && a[curl-1] < mx[curr]; curl--);
if(curl < mid+1 && curr > mid+1 && curr - curl == mx[curr] - mi[curr]) ans++;
}
// min in L, max in R
{
for(int i = mid+1; i <= r; i++) sum[mx[i]-i+n]++;
int L = mid+1, R = mid;
for(int i = mid+1; i <= r; i++) sumL[mx[i]-i+n]++;
for(int i = mid; i >= l; i--)
{
for(; R < r && mi[i] < mi[R+1]; R++) sumR[mx[R+1]-(R+1)+n]++;
for(; L <= r && mx[i] > mx[L] ; L++) sumL[mx[L]-L+n]--;
if(L <= R) ans += sumL[mi[i]-i+n] + sumR[mi[i]-i+n] - sum[mi[i]-i+n];
}
for(int i = mid+1; i <= R; i++) sumR[mx[i]-i+n]--;
for(int i = L; i <= r; i++) sumL[mx[i]-i+n]--;
for(int i = mid+1; i <= r; i++) sum[mx[i]-i+n]--;
}
// max in L, min in R
{
for(int i = mid+1; i <= r; i++) sum[mi[i]+i]++;
int L = mid, R = mid+1;
for(int i = mid+1; i <= r; i++) sumR[mi[i]+i]++;
for(int i = mid; i >= l; i--)
{
for(; R <= r && mi[i] < mi[R]; R++) sumR[mi[R]+R]--;
for(; L < r && mx[i] > mx[L+1] ; L++) sumL[mi[L+1]+(L+1)]++;
if(R <= L) ans += sumL[mx[i]+i] + sumR[mx[i]+i] - sum[mx[i]+i];
}
for(int i = mid+1; i <= L; i++) sumL[mi[i]+i]--;
for(int i = R; i <= r; i++) sumR[mi[i]+i]--;
for(int i = mid+1; i <= r; i++) sum[mi[i]+i]--;
}
dc(l,mid); dc(mid+1, r);
}
void main()
{
n = read();
for(int i = 1, j; i <= n; i++) j = read(), a[j] = read();
dc(1,n); printf("%lld\n",ans);
}
}
int main()
{
runzhe2000::main();
}