题目:http://www.hihocoder.com/problemset/problem/1391?sid=895605
官方题解:

分析:
我们可以预处理出导弹到达A的每个时间段,这样问题就转化成了求[x,x+TA]覆盖最大的时间段相应的代价和,这个范围内的导弹是可以防御住的,那么剩下的就是无法防御的。
所以用树状数组求解,时间的数据范围有点大,离散化一下即可。
代码:
using namespace std;
typedef long long ll;
const int N=1e5+9;
ll c[N];
int lowbit(int x) {
return x&(-x);
}
ll getsum(int x) {
ll sum=0;
for(int i=x; i>0; i-=lowbit(i))sum+=c[i];
return sum;
}
void add(int x,ll v) {
for(int i=x; i<N; i+=lowbit(i))c[i]+=v;
}
struct Item {
ll l,r,v;
bool operator < (const Item& rhs)const {
return r<rhs.r;
}
} a[N];
ll b[N];
map<ll,int>id;
int main() {
//freopen("f.txt","r",stdin);
ll Ta,Tb,Sb,s,t,v;
int n,m;
while(~scanf("%lld%lld",&Ta,&Tb)) {
memset(c,0,sizeof(c));
id.clear();
scanf("%lld",&Sb);
scanf("%d%d",&n,&m);
ll Eb=Tb+Sb,sum=0;
int cnt=0;
for(int i=1; i<=n; i++) {
scanf("%lld%lld%lld",&s,&t,&v);
if(s+t>=Sb&&s+t<=Eb) {
a[cnt].l=s+2*t;
a[cnt].r=s+2*t+(Eb-s-t)/(2*t)*2*t;
a[cnt].v=v;
cnt++;
sum+=v;
}
}
for(int i=1; i<=m; i++) {
scanf("%lld%lld%lld",&s,&t,&v);
a[cnt].l=s+t;
a[cnt].v=v;
sum+=v;
if(s+2*t<Sb||s+2*t>Eb)a[cnt].r=a[cnt].l;
else a[cnt].r=s+3*t+(Eb-s-2*t)/(2*t)*2*t;
cnt++;
}
int tot=0;
for(int i=0; i<cnt; i++) {
b[tot++]=a[i].l;
b[tot++]=a[i].r;
b[tot++]=a[i].r-Ta;
}
sort(b,b+tot);
tot=unique(b,b+tot)-b;
for(int i=0; i<tot; i++)id[b[i]]=i+1;
sort(a,a+cnt);
ll ans=0;
for(int i=0; i<cnt; i++) {
add(id[a[i].l],a[i].v);
ans=max(ans,getsum(id[a[i].r])-getsum(id[a[i].r-Ta]-1));
}
printf("%lld\n",sum-ans);
}
return 0;
}

本文介绍了一种使用树状数组解决特定导弹防御问题的方法。通过对导弹到达时间的预处理,将问题转化为求时间段内最大代价和的问题,并通过离散化处理大的时间范围。最后给出了详细的代码实现。

被折叠的 条评论
为什么被折叠?



