Killing Monsters(看似线段树)HDU 4970

题目就不放了,占空间

然后找了一个官方题解,开始有点看不懂,后来懂了

看别人的题解都说题目好懂,然而并不觉得,我做了一段时间才发现自己连题目都理解错了。

题目意思:

有n个塔,每个塔最多攻击一次,造成d伤害,攻击区间为L到R,然后有k个怪兽,分别在不同的点上,它们要走到n点(最右边的点),问有多少个怪物存活。

一开始一直没看到怪物走向n点的条件,怎么都看不懂。

然后,想到的普通做法就是,根据塔的信息进行区间更新,将区间的值加上伤害值。

由于所有怪要走到n点,所以我们开一个后缀和数组,记录每个点到n点的shan伤害值,最后回答询问。

如果用普通的线段树做法,是n*log(n)的算法,很遗憾,会超时,md,这样算法都超时,真够坑的啊。

然后优化的做法是,对于区间更新,只需要差分一下,这里就有个小知识点了,更新区间的值,只需要把左端点值+val,右端点右边一个点-val,然后扫一遍相加就能求出每个点的值,这个知识点,只要做过线段树的都应该知道吧

AC的代码(真的都懒得打):

//#pragma warning (disable:4786)
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <queue>
#include <stack>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

#define INF 1e18

typedef __int64 LL;
const int MAXN = 200017;
int num[MAXN];
LL sum[MAXN];
int main()
{
    int l,r,d;
    int tow,n,m,x;
    LL h;
    while(scanf("%d",&n) && n)
    {
        scanf("%d",&tow);
        memset(num,0,sizeof(num));
        memset(sum,0,sizeof(sum));
        for(int i = 0; i < tow; i++)
        {
            scanf("%d%d%d",&l,&r,&d);
            num[l] += d;
            num[r+1] -= d;
        }
 
        for(int i = 1; i <= n; i++)
        {
            sum[i] = sum[i-1]+num[i];
        }
 
        for(int i = n; i >= 1; i--)
        {
            sum[i] = sum[i+1]+sum[i];
        }
        int cont = 0;
        scanf("%d",&m);
        for(int i = 0; i < m; i++)
        {
            scanf("%I64d%d",&h,&x);
            if(sum[x] < h)
            {
                cont++;
            }
        }
        printf("%d\n",cont);
    }
    return 0;
}

下面是TLE的代码:

我更愿意写这个版本的,接地气

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
typedef long long ll;
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define fork(l,r) for( int k = 1 ; k <= r ; k++ )
#define mem(a,val) memset(a,val,sizeof a)
#define lef rt<<1
#define rig rt<<1|1
#define mid (l+r)>>1
using namespace std;

const int maxn = 1e5+5;
ll tree[maxn<<2],add[maxn<<2];
int n,m;
int L,R;
ll backsum[maxn];
int read( )
{
    char ch = getchar();
    int x = 0;
    while( ch < '0' || ch >'9'  )
        ch = getchar();
    while( ch >= '0' && ch <= '9' )
    {
        x = x*10+ch-'0';
        ch = getchar();
    }
    return x;
}
ll longread( )
{
    char ch = getchar();
    ll x = 0;
    while( ch < '0' || ch >'9'  )
        ch = getchar();
    while( ch >= '0' && ch <= '9' )
    {
        x = x*10+ch-'0';
        ch = getchar();
    }
    return x;
}
void pushdown( int rt )
{
    if( add[rt] )
    {
        tree[lef] += add[rt];
        tree[rig] += add[rt];
        add[lef] += add[rt];
        add[rig] += add[rt];
        add[rt] = 0;
    }
}
void change( int rt )
{
    tree[rt] = tree[lef]+tree[rig];
}
void update( int l,int r,int rt,ll val )
{
    if( l >= L && r <= R )
    {
        tree[rt] += val;
        add[rt] += val;
        return;
    }
    pushdown(rt);
    int m = mid;
    if( m >= L )
        update(l,m,lef,val);
    if( m < R )
        update(m+1,r,rig,val);
    //change(rt);
}
ll query( int l,int r,int rt,int pos )  //单点查询
{
    if( l == r )
        return tree[rt];
    int m = mid;
    pushdown(rt);
    if( m >= pos )
        return query(l,m,lef,pos);
    else return query(m+1,r,rig,pos);
}
int main()
{
    while( scanf("%d",&n) == 1 && n )
    {
        ll d;
        //scanf("%d",&m);
        m = read();
        int rr = n<<2;
        fori(1,rr)
        {
            tree[i] = 0;
            add[i] = 0;
        }

        //fori(1,m)
        for( int i = 1 ; i <= m ; i++ )
        {
            L = read();
            R = read();
            d = longread();
            //scanf("%d %d %I64d",&L,&R,&d);
            update(1,n,1,d);
        }
        ll total = 0;
        for( int i = n ; i >= 1 ; i-- )
        {
            total += query(1,n,1,i);
            backsum[i] = total;
            //cout<<backsum[i]<<" ";
        }
        int k,pos,ans = 0;
        ll hp;
        scanf("%d",&k);
        while( k-- )
        {
            hp = longread();
            pos = read();
            //scanf("%I64d %d",&hp,&pos);
            if( backsum[pos] < hp ) //造成的伤害小于hp 则存活
                ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}
/*
5 5
1 3 1
2 4 2
4 5 1
3 5 4
1 2 2
7
5 3
4 2
5 5
5 1
4 4
4 3
7 2

5 5
1 3 1
2 4 2
4 5 1
3 5 4
1 2 2
7
8 3
4 2
9 5
5 1
5 4
7 3
7 2


5 5
1 3 3
2 4 5
4 5 6
3 5 4
1 2 2
7
8 3
4 3
9 5
7 2
12 4
7 3
14 2


*/

猜你喜欢

转载自blog.csdn.net/qq_39627843/article/details/81636046