E - Cloudy Day ( 差分 )
题目连接:https://vjudge.net/problem/HackerRank-cloudy-day
题意:在一个二维坐标系,有若干房子( 用一个点表示,无宽度 ),房子里有住的人 ,和若干乌云( 有长宽 )。现在问只去掉一块乌云能让最多的人头顶没有乌云。
上图解释:乌云覆盖的面积是3,4,5, 在5上的房子就被乌云遮盖了。
思路:因为只能去掉一块乌云,所有被两块乌云覆盖的点一定无法看见太阳了。当只有一块乌云遮盖时我们统计是哪一块乌云给这块乌云加上这个点的人数,当没有乌云时,直接在最终答案上加当前人数。然后我们遍历所有乌云找到人数最大的给加上。
对于当前是哪一块乌云?我们可以用差分来维护,维护一个cha值 [L,R] 时 cha[L] += 乌云编号 cha[R+1] -= 乌云编号。再维护一个ci数组,来记录当前是几个乌云,[L,R] 时 ci[L] ++ ; ci[R+1] --; 这样当我们当前的 ci 是1时cha的值正好是这片乌云的编号。
注意:wa20的点是因为,房子可以重叠。所以在统计每个点人数的时候用+=
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 5e5+10;
int peoplenum[maxn],peopleid[maxn];
int pos[maxn],wid[maxn];
int people[maxn];
int n,m;
int cha[maxn];
int ans[maxn],posi,now;
int ci[maxn];
int b[maxn],cnt;
signed main()
{
cin >> n;
for ( int i=0; i<n; i++ ) {
scanf("%lld",&peoplenum[i]);
}
for ( int i=0; i<n; i++ ) {
scanf("%lld",&peopleid[i]);
b[cnt++] = peopleid[i];
}
cin >> m;
for ( int i=0; i<m; i++ ) {
scanf("%lld",&pos[i]);
}
for ( int i=0; i<m; i++ ) {
scanf("%lld",&wid[i]);
b[cnt++] = pos[i]-wid[i];
b[cnt++] = pos[i]+wid[i];
}
sort(b,b+cnt);
cnt = unique(b,b+cnt)-b;
for ( int i=0; i<n; i++ ) {
int p = lower_bound(b,b+cnt,peopleid[i])-b+1;
people[p] += peoplenum[i];
}
for ( int i=0; i<m; i++ ) {
int l = lower_bound(b,b+cnt,pos[i]-wid[i])-b+1;
int r = lower_bound(b,b+cnt,pos[i]+wid[i])-b+1;
cha[l] += (i+1); ci[l] ++;
cha[r+1] -= (i+1); ci[r+1]--;
}
int tot = 0;
int answer = 0;
now = 0; posi = 0;
for ( int i=1; i<=cnt; i++ ) {
now += cha[i];
tot += ci[i];
if ( tot==0 ) {
answer += people[i];
}
else if ( tot==1 ) {
ans[now] += people[i];
}
}
sort(ans+1,ans+m+1,greater<int>());
answer += ans[1];
cout << answer << endl;
return 0;
}