题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4970
题目大意:
类似于一类塔防游戏。monster只能在一条长为N的直线上移动,有m个塔,每个塔有自己的防守范围以及在范围内每个点的伤害值;有k个monster,每个monster有自己的HP,以及刚开始出现在直线上的位置。问最后有多少monster能活着。
此题就是很裸的区间修改,区间查询问题。
和上次多校赛的塔防那题差了很多,属于签到题范围。
有两种方法,一种是利用树状数组的区间修改,点查询的方法做,维护一个数组attack[i]代表从i到n会受到的总伤害。复杂度为O(n*logn);
第二种方法是建立一个temp数组。对于每个塔的属性(l,r,a)(范围为[l,r],伤害为a),使temp[l]=a,temp[r+1]=-a;扫完所有塔之后,求其前缀和数组,这个前缀和数组中每一个元素就代表怪物在当前点会受到的伤害,再从后面往前面扫一遍,即可得到方法一中的attack数组。复杂度为O(n)。
最后计算有多少个monster的HP能大于他走到最后受到的总伤害,即可得到答案。
方法一的代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define N 100100
using namespace std;
long long c[N];
long long sum[N];
long long n;
long long getnum(long long x)
{
long long rnt=0;
for(long long i=x;i<=n;i+=(i&(-i)))
{
rnt+=c[i];
}
return rnt;
}
void add(long long i,long long a)
{
while(i>=1)
{
c[i]+=a;
i-=(i&(-i));
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("D:/in.txt","r",stdin);
#endif // ONLINE_JUDGE
while(~scanf("%I64d",&n)&&n)
{
long long m;
memset(c,0,sizeof(c));
//memset(sum,0,sizeof(sum));
scanf("%I64d",&m);
while(m--)
{
long long l,r,a;
scanf("%I64d%I64d%I64d",&l,&r,&a);
add(r,a),add(l-1,-a);
}
sum[n+1]=0;
for(long long i=n;i>=1;i--)
{
sum[i]=sum[i+1]+getnum(i);
}
long long K;
scanf("%I64d",&K);
long long ans=0;
while(K--)
{
long long h,x;
scanf("%I64d%I64d",&h,&x);
if(h>=sum[x]) ans++;
}
printf("%I64d\n",ans);
}
return 0;
}
第二种方法是题解的方法,大家可以自己试着写一下~