hdu 4970 Killing Monsters 策略O(n)/线段树O(nlogn)+快速读入 2014 Multi-University Training Contest 9-1011

本文探讨了解决塔防游戏中怪物被消灭数量的优化算法,对比了线段树与O(n)算法的效率,并通过代码实现详细解释了两种方法。重点介绍了更简便的O(n)算法及其应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

塔防游戏,一条n长的路上,有m个炮台,可以覆盖[li,ri]范围,威力ci,即每一秒,炮塔可以对范围 内的怪物可以造成ci点伤害。只有有q只怪物,每只怪物有hi点血,出现位置为xi;当怪物血量减少到0或以下时消失,怪物一直朝n位置前进。问有几只怪物可以离开这条路。

题解:

一开始看到这个题目就想到了线段树,最简单那种线段求和。不过作者好坑人啊,卡大数据。。TLE,之后没去想O(n)算法,直接快速读入险过。

其实这个有更加简便的方法(习惯性想到线段树害死人啊。)详细的看代码,不好说明,就是用e数组记录边界就可以了。


代码:

1.O(n)算法

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cctype>
using namespace std;

#define LL __int64
const int maxn=1e5+10;
int e[maxn];
LL sum[maxn];
inline int readint()
{
    int x=0;
    char ch;
    ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}
inline LL readint2()
{
    LL x=0;
    char ch;
    ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}
int main()
{
    int n;
    while(n=readint())
    {
        memset(e,0,sizeof(e));
        int i,j,k,m,a,b,c;
        //scanf("%d",&m);
        m=readint();
        for(i=0;i<m;i++)
        {
            //scanf("%d%d%d",&a,&b,&c);
            a=readint();
            b=readint();
            c=readint();
            e[a-1]-=c;
            e[b]+=c;
        }
        sum[n+1]=0;
        LL x=0;
        for(i=n;i>=1;i--)
        {
            x+=e[i];
            sum[i]=sum[i+1]+x;
        }
        //for(i=1;i<=n;i++)printf("%I64d\n",sum[i]);
        int q,y,ans=0;
        //scanf("%d",&q);
        q=readint();
        while(q--)
        {
            //scanf("%I64d%d",&x,&y);
            x=readint2();
            y=readint();
            if(x>sum[y])ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}


2.线段树

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cctype>
using namespace std;

#define LL __int64
const int maxn=1e5+10;
struct node{
    int l,r;
    LL w,addv;
}e[maxn*4];
void build(int a,int b,int c)
{
    e[c].l=a;e[c].r=b;e[c].w=e[c].addv=0;
    if(a==b)return ;
    int mid=(a+b)>>1;
    build(a,mid,c<<1);
    build(mid+1,b,(c<<1)|1);
}
void push_down(int c)
{
    if(e[c].addv)
    {
        e[c<<1].addv+=e[c].addv;e[(c<<1)|1].addv+=e[c].addv;
        e[c<<1].w+=e[c].addv*(e[c<<1].r-e[c<<1].l+1);
        e[(c<<1)|1].w+=e[c].addv*(e[(c<<1)|1].r-e[(c<<1)|1].l+1);
        e[c].addv=0;
    }
}
void update(int a,int b,int c,int val)
{
    if(e[c].l==a&&e[c].r==b)
    {
        e[c].w+=(LL)val*(e[c].r-e[c].l+1);
        e[c].addv+=val;
        return ;
    }
    push_down(c);
    int mid=(e[c].l+e[c].r)>>1;
    if(b<=mid)update(a,b,c<<1,val);
    else if(a>mid)update(a,b,(c<<1)|1,val);
    else
    {
        update(a,mid,c<<1,val);
        update(mid+1,b,(c<<1)|1,val);
    }
    e[c].w=e[c<<1].w+e[(c<<1)|1].w;
}
LL query(int a,int b,int c)
{
    if(e[c].l==a&&e[c].r==b)
    {
        return e[c].w;
    }
    push_down(c);
    int mid=(e[c].l+e[c].r)>>1;
    if(b<=mid)return query(a,b,c<<1);
    else if(a>mid)return query(a,b,(c<<1)|1);
    else return query(a,mid,c<<1)+query(mid+1,b,(c<<1)|1);
}
int readint()
{
    int x=0;
    char ch;
    ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}
LL readint2()
{
    LL x=0;
    char ch;
    ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}
int main()
{
    //freopen("D:\\in.txt","r",stdin);
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        int i,j,k,m,a,b,c,f,q,ans=0;
        LL x,d;
        build(1,n,1);
        scanf("%d",&m);
        for(i=0;i<m;i++)
        {
            //scanf("%d%d%d",&a,&b,&c);
            a=readint();
            b=readint();
            c=readint();
            update(a,b,1,c);
        }
        scanf("%d",&q);
        while(q--)
        {
            //scanf("%I64d%d",&d,&f);
            d=readint2();
            f=readint();
            x=query(f,n,1);
            //cout<<x<<endl;
            if(x<d)ans++;
        }
        //for(i=1;i<=n;i++)printf("*%I64d\n",query(i,n,1));
        printf("%d\n",ans);
    }
    return 0;
}
/*
10
5
1 7 1
3 4 2
2 9 4
7 10 8
7 7 2
4
8 10
7 10
9 10
77 1
*/






评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值