题目
题目描述
In this problem you will meet the simplified model of game Pudding Monsters.
An important process in developing any game is creating levels. A game field in Pudding Monsters is an n×nn×n rectangular grid, nn of its cells contain monsters and some other cells contain game objects. The gameplay is about moving the monsters around the field. When two monsters are touching each other, they glue together into a single big one (as they are from pudding, remember?).
Statistics showed that the most interesting maps appear if initially each row and each column contains exactly one monster and the rest of map specifics is set up by the correct positioning of the other game objects.
A technique that’s widely used to make the development process more efficient is reusing the available resources. For example, if there is a large n×nn×n map, you can choose in it a smaller k×kk×k square part, containing exactly kk monsters and suggest it as a simplified version of the original map.
You wonder how many ways there are to choose in the initial map a k×kk×k ( 1<=k<=n1<=k<=n ) square fragment, containing exactly kk pudding monsters. Calculate this number.
输入格式
The first line contains a single integer nn ( 1<=n<=3×10^{5}1<=n<=3×10
5
) — the size of the initial field.
Next nn lines contain the coordinates of the cells initially containing monsters. The ii -th of the next lines contains two numbers r_{i},c_{i}r
i
,c
i
( 1<=r_{i},c_{i}<=n1<=r
i
,c
i
<=n ) — the row number and the column number of the cell that initially contains the ii -th monster.
It is guaranteed that all r_{i}r
i
are distinct numbers and all c_{i}c
i
are distinct numbers.
输出格式
Print the number of distinct square fragments of the original field that can form a new map.
题意翻译
给定一个 n \times nn×n 的棋盘,其中有 nn 个棋子,每行每列恰好有一个棋子。
求有多少个 k \times kk×k 的子棋盘中恰好有 kk 个棋子。
n \le 3 \times 10^5n≤3×10
5
。
输入输出样例
输入 #1复制
5
1 1
4 3
3 2
2 4
5 5
输出 #1复制
10
思路
首先把它拍扁到一个序列上应该不难想到,然后就是求满足
max
[
l
,
r
]
−
min
[
l
,
r
]
=
r
−
l
\max[l,r]-\min[l,r]=r-l
max[l,r]−min[l,r]=r−l 的
[
l
,
r
]
[l,r]
[l,r] 个数,其中
max
[
l
,
r
]
\max[l,r]
max[l,r] 表示区间中的最大值。
套路地枚举
r
r
r。
我们尝试维护
max
[
l
,
r
]
−
min
[
l
,
r
]
+
l
\max[l,r]-\min[l,r]+l
max[l,r]−min[l,r]+l,然后我们需要支持有多少个这个式子等于
r
r
r。
这个时候你可以秒出一个算法:用树状数组去维护差分,开两个单调栈,然后退栈就做一个区间修改……
然后就假掉了,因为退栈的时候有可能得遍历一遍另一个栈,复杂度直接被卡成平方带一个 log 比暴力还劣。
既然不能直接维护出现次数,我们不妨用线段树去维护在
[
1
,
r
]
[1,r]
[1,r] 中有多少个
l
l
l 满足
max
[
l
,
r
]
−
min
[
l
,
r
]
+
l
=
r
\max[l,r]-\min[l,r]+l=r
max[l,r]−min[l,r]+l=r,利用单调栈,我们需要的就是区间加和改变等式的右边……
然后就又不会了。
其实我们距离正解只有一步之遥。我们发现
max
[
l
,
r
]
−
min
[
l
,
r
]
≥
r
−
l
\max[l,r]-\min[l,r]\ge r-l
max[l,r]−min[l,r]≥r−l,所以我们维护
max
[
l
,
r
]
−
min
[
l
,
r
]
+
l
\max[l,r]-\min[l,r]+l
max[l,r]−min[l,r]+l 的最小值及出现次数即可。
代码
#include<bits/stdc++.h>
#define ll long long
#define ls p<<1
#define rs p<<1|1
#define md ((l+r)>>1)
using namespace std;
const int N = 3e5 + 7;
int n,a[N],sx[N],tx,sn[N],tn;
map <int,int> p;
struct T
{
int l,r,x,c,z;
} t[N<<2];
ll ans;
void build(int p,int l,int r)
{
t[p].l = l,t[p].r = r,t[p].c = r - l + 1;
if(l == r) return;
build(ls,l,md);
build(rs,md + 1,r);
}
void add(int p,int x)
{
t[p].x += x,t[p].z += x;
}
void upd(int p,int l,int r,int x) {
if(t[p].l >= l && t[p].r <= r) return add(p,x);
if(t[p].z) add(ls,t[p].z),add(rs,t[p].z),t[p].z = 0;
if(l <= md) upd(ls,l,r,x);
if(r > md) upd(rs,l,r,x);
t[p].x = min(t[ls].x,t[rs].x);
t[p].c = (t[ls].x == t[p].x ? t[ls].c : 0) + (t[rs].x == t[p].x ? t[rs].c : 0);
}
int main() {
scanf("%d",&n);
for(int i = 1,x,y; i <= n; i++) scanf("%d%d",&x,&y),a[x] = y;
build(1,1,n);
for(int i = 1; i <= n; i++) {
while(tx && a[sx[tx]] < a[i]) upd(1,sx[tx-1] + 1,sx[tx],-a[sx[tx]]),--tx;
while(tn && a[sn[tn]] > a[i]) upd(1,sn[tn-1] + 1,sn[tn],a[sn[tn]]),--tn;
upd(1,p[a[i]] + 1,i,-1),p[a[i]] = sx[++tx] = sn[++tn] = i;
upd(1,sx[tx-1] + 1,i,a[i]),upd(1,sn[tn-1] + 1,i,-a[i]);
ans += t[1].c;
}
printf("%d\n",ans);
return 0;
}