题面
问题描述
由于各种原因,桐人现在被困在
U
n
d
e
r
W
o
r
l
d
Under World
UnderWorld(以下简称
U
W
UW
UW)中,而
U
W
UW
UW 马上要迎来最终的压力测试——魔界入侵。
唯一一个神一般存在的
A
d
m
i
n
i
s
t
r
a
t
o
r
Administrator
Administrator 被消灭了,靠原本的整合骑士的力量
是远远不够的。所以爱丽丝动员了
U
W
UW
UW 全体人民,与整合骑士一起抗击魔族。
在
U
W
UW
UW 的驻地可以隐约看见魔族军队的大本营。整合骑士们打算在魔族入侵前发动一次奇袭,袭击魔族大本营!
为了降低风险,爱丽丝找到了你,一名优秀斥候,希望你能在奇袭前对魔族大本营进行侦查,并计算出袭击的难度。
经过侦查,你绘制出了魔族大本营的地图,然后发现,魔族大本营是一个
N
×
N
N×N
N×N 的网格图,一共有
N
N
N 支军队驻扎在一些网格中(不会有两只军队驻扎在一起)。
在大本营中,每有一个
k
×
k
(
1
≤
k
≤
N
)
k×k\ (1≤k≤N)
k×k (1≤k≤N) 的子网格图包含恰好
k
k
k 支军队,我们袭击的难度就会增加
1
1
1 点。
现在请你根据绘制出的地图,告诉爱丽丝这次的袭击行动难度有多大。
输入格式
第一行,一个正整数
N
N
N,表示网格图的大小以及军队数量。
接下来
N
N
N 行,每行两个整数,
X
i
,
Y
i
X_i,Y_i
Xi,Yi,表示第i支军队的坐标。
保证每一行和每一列都恰有一只军队,即每一个
X
i
X_i
Xi 和每一个
Y
i
Y_i
Yi 都是不一样的。
输出格式
一行,一个整数表示袭击的难度。
样例
Input
5
1 1
3 2
2 4
5 5
4 3
Output
10
题解
唉,考试的时候没有看到加粗的那行字,直接
G
G
GG
GG。
根据加粗的那行字,每行每列有且只有一个大本营,明显我们可以把二维的图映射到一个序列上,将二维问题转化为一维问题。
行号对应每个大本营在序列上的位置,列号对应每个大本营在序列上的权值。
不难发现这
n
n
n 个大本营就转化为了一个
1
1
1~
n
n
n 的排列。而我们要求的问题,就转化为了满足
m
a
x
−
m
i
n
=
R
−
L
max - min = R - L
max−min=R−L 的区间 [
L
,
R
L,R
L,R] 的个数为多少。
因为
m
a
x
,
m
i
n
max,min
max,min 分别对应着列号的最大最小值,
R
,
L
R,L
R,L 分别对应着行号的最大最小值。满足上诉条件的区间就代表一个边长为
R
−
L
R - L
R−L(或者
m
a
x
−
m
i
n
max - min
max−min)的正方形里有
R
−
L
R - L
R−L(或者
m
a
x
−
m
i
n
max - min
max−min)个大本营。
注意我们要把二维矩阵中包含的所有正方形都统计完,而它们在序列上分别对应着区间 [
1
,
1
1,1
1,1],[
1
,
2
1,2
1,2]…[
1
,
n
1,n
1,n]…[
n
,
1
n,1
n,1],[
n
,
2
n,2
n,2]…[
n
,
n
n,n
n,n]。
尝试用线段树 + 扫描线维护。
将上述等式移项,记
M
i
n
=
m
a
x
−
m
i
n
−
R
+
L
Min = max - min - R + L
Min=max−min−R+L,因为这是一个
1
1
1 ~
n
n
n 的排列,根据鸽巢原理,显然有
m
a
x
−
m
i
n
≥
R
−
L
max - min \geq R - L
max−min≥R−L,所以有:
M
i
n
≥
0
Min\geq 0
Min≥0,那么显然满足条件的序列的
M
i
n
Min
Min 值为
0
0
0,所以我们只用在线段树上维护
M
i
n
Min
Min就好了,因为还要求个数,所以再维护值为
M
i
n
Min
Min 的个数。
当扫描到
R
R
R 时,线段树上的单位节点 [
l
,
r
l,r
l,r] 储存区间 [
l
,
R
l,R
l,R],[
l
+
1
,
R
l + 1,R
l+1,R]…[
r
,
R
r,R
r,R] 对应的
M
i
n
Min
Min 的值,和值为
M
i
n
Min
Min 的区间的个数。
那么我们就得到了下述的基本框架,线段树的细节见代码:
- 当每次 R + + R++ R++ 后, M i n Min Min 的值显然会减一,区间修改。
- 对于 m a x , m i n max,min max,min 的维护,我们可以用两个单调栈。
- 每次单调栈的栈顶元素更新时,显然对于 s t a t o p − 1 sta_{top - 1} statop−1 ~ s t a t o p sta_{top} statop(还未更新)对应的序列的位置的 M i n Min Min 值都因为 m a x max max 或 m i n min min 的值的改变而受到了影响需要改变,再次进行区间修改。
- 每次维护结束后 q u e r y query query 一次累加入答案。
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 3e5 + 5;
struct SegmentTree {
#define M N << 2
int l[M],r[M],Min[M],tag[M];
long long cnt[M];
void build(int p,int lf,int rg) {
l[p] = lf,r[p] = rg;
if(lf == rg) {
Min[p] = lf; cnt[p] = 1;
return;
}
int mid = (lf + rg) >> 1;
build(p << 1,lf,mid);
build(p << 1 | 1,mid + 1,rg);
Min[p] = Min[p << 1];
}
inline void pushdown(int p) {
if(!tag[p]) return;
Min[p << 1] += tag[p];
Min[p << 1 | 1] += tag[p];
tag[p << 1] += tag[p];
tag[p << 1 | 1] += tag[p];
tag[p] = 0;
}
inline void pushup(int p) {
Min[p] = min(Min[p << 1],Min[p << 1 | 1]); cnt[p] = 0;
if(Min[p] == Min[p << 1]) cnt[p] += cnt[p << 1];
if(Min[p] == Min[p << 1 | 1]) cnt[p] += cnt[p << 1 | 1];
}
void add(int p,int L,int R,int k) {
if(L <= l[p] && r[p] <= R) {
Min[p] += k; tag[p] += k;
return;
}
pushdown(p);
int mid = (l[p] + r[p]) >> 1;
if(L <= mid) add(p << 1,L,R,k);
if(R > mid) add(p << 1 | 1,L,R,k);
pushup(p);
}
long long query(int p,int L,int R) {
if(L <= l[p] && r[p] <= R) return Min[p] == 0 ? cnt[p] : 0;
int mid = (l[p] + r[p]) >> 1;
long long ans = 0; pushdown(p);
if(L <= mid) ans += query(p << 1,L,R);
if(R > mid) ans += query(p << 1 | 1,L,R);
return ans;
}
}tr;
struct data {
int x,y;
bool operator < (const data n) const {
return x < n.x;
}
}a[N],sta1[N],sta2[N];
inline int read() {
int x = 0,flag = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')flag = -1;ch = getchar();}
while(ch >='0' && ch <='9'){x = (x << 3) + (x << 1) + ch - 48;ch = getchar();}
return x * flag;
}
int main() {
int n = read(); int top1 = 0,top2 = 0;
for(int i = 1; i <= n; i++)
a[i].x = read(),a[i].y = read();
sort(a + 1,a + 1 + n); tr.build(1,1,n);
long long ans = 0;
for(int i = 1; i <= n; i++) {
tr.add(1,1,n,-1);
while(top1 && sta1[top1].y < a[i].y)
tr.add(1,sta1[top1 - 1].x + 1,sta1[top1].x,a[i].y - sta1[top1].y),--top1;
sta1[++top1] = (data) {i,a[i].y};
while(top2 && sta2[top2].y > a[i].y)
tr.add(1,sta2[top2 - 1].x + 1,sta2[top2].x,sta2[top2].y - a[i].y),--top2;
sta2[++top2] = (data) {i,a[i].y};
ans += tr.query(1,1,i);
}
printf("%lld",ans);
return 0;
}