题目链接:
https://nanti.jisuanke.com/t/15773
题解:
先对点按x排序
设Xa<=Xb
当k<=40时,可以用中等难度的方法枚举Xa再枚举Xb,当Xb-Xa>k时不符合条件,并且更大的Xb也不符合条件,所以不接下去枚举Xb。因为楼层高度最高为20所以最多计算20*20次(这里更正一下,应该是20*m次m具体为多少我也不知道,但肯定不超过40,望dalao指教)
k>40时,从枚举Xa,再对Xb进行二分,找到第一个Xb-Xa>=k-40,则在Xa至Xb之间的核心部门到Xa的距离都是<=k的,因为楼层最高为20,然后继续从Xb用开始枚举Xb,一直到Xb-Xa>k为止,同样最多计算20*20次(20*m次)
PS:表达可能不太清楚,请见谅
#include<bits/stdc++.h>
using namespace std;
#define MAX_N 200005
#define inf 0x3f3f3f3f
#define LL long long
#define uLL unsigned long long
const LL mod = 1e8;
const LL INF = 1e18;
typedef pair<int, int>P;
const double eps = 1e-6;
int h[MAX_N];
P p[MAX_N];
int minsum[MAX_N][20];
void init_RMQ(int n)
{
for(int i=1;i<=n;i++)
minsum[i][0] = h[i];
int k = log2(1.0*n);
for(int j=1;j<=k;j++) {
for(int i=1;i<=n;i++) {
if(i+(1<<j)-1<=n) {
minsum[i][j] = min(minsum[i][j-1], minsum[i+(1<<(j-1))][j-1]);
}
}
}
}
int getMin(int i,int j)
{
int k = (int)log2(1.0*(j-i+1));
return min(minsum[i][k], minsum[j-(1<<k)+1][k]);
}
int main()
{
int n, k, m;
cin >> n >> k;
for(int i=1; i<=n; i++) {
scanf("%d", &h[i]);
}
init_RMQ(n);
cin >> m;
for(int i=0; i<m; i++) {
int x, y;
cin >> x >> y;
p[i] = P(x, y);
}
sort(p, p+m);
LL ans = 0;
if(k<=40) {
for(int i=0; i<m; i++) {
for(int j=i+1; j<m; j++) {
if(p[j].first-p[i].first>k)
break;
int low = min(p[i].second, p[j].second);
low = min(low, getMin(p[i].first, p[i].second));
int tmp = p[i].second + p[j].second - 2*low + abs(p[i].first - p[j].first);
if(tmp <= k)
ans++;
}
}
}
else {
for(int i=0; i<m; i++) {
int pos = lower_bound(p, p+m, P(p[i].first+k-40, 0)) - p;//p[i+1]-p[pos]之间的点到p[i]的距离都是小于等于k的
ans += (LL)(pos-i-1);
for(int j=pos; j<m; j++) {
if(p[j].first-p[i].first>k)
break;
int low = min(p[i].second, p[j].second);
low = min(low, getMin(p[i].first, p[j].first));
int tmp = p[i].second + p[j].second - 2*low + abs(p[i].first - p[j].first);
if(tmp <= k)
ans++;
}
}
}
cout << ans << endl;
}