卡牌对战游戏(线段树)

题目描述
Alice和Bob都非常喜欢卡牌对战游戏,在一次对战游戏中,Alice召唤了 n个随从,其中第 i个随从的生命值ai,攻击力是b i,现在是Bob的轮次,他需要尽可能降低场攻,Bob有一张名叫“亵渎”的法术牌,在自己的回合开始时,Bob可以指定任意一名 Alice的随从,对它发动“亵渎”,该随从会直接死亡。此后,当有随从死亡时,Bob可以继续指定随从发动“亵渎”,但是必须保证指定的随从在上一次死亡随从的右边。当Bob在第i轮指定发动“亵渎”的随从,其生命值与上一轮死亡的随从的生命值差值的绝对值不超过d时,则第i轮指定的随从会死亡。否则,一旦被“亵渎”的随从没有死亡,“亵渎”效果终止。你需要计算的是,当Bob采用最优策略时,最多能降低的场攻是多少。(降低的场攻指所有死亡的随从攻击力之和)

输入描述:
第一行输入n和d,n为Alice场上随从个数。 (1≤n,d≤100000)
接下来n行每行输入两个正整数,表示第i个随从的生命值和攻击力。 (1≤ai ,b i≤100000)

输出描述:
输出一行,代表Bob采取最优策略时,最多能够降低的场攻。

示例1
输入
2 5
10 10
16 11

输出
11

思路
每次询问,借助线段树查找(a-d,a+d)这个区间内的最大值,并进行更新

代码实现

#pragma GCC optimize(3,"Ofast","inline")
#include
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=100005;
const int M=20016;
const int INF=0x3f3f3f3f;
const ll LINF=1e18;
const ull sed=31;
const ll mod= 998244353;
const double eps=1e-5;
const double PI=acos(-1.0);
typedef pair<int,int>P;
typedef pair<double,double>Pd;
    
template<class T>void read(T &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return;
}

int n,d;
ll T[N<<2],ans;

void update(int pos,ll val,int l,int r,int rt)
{
    if(l==r)
    {
        T[rt]=max(T[rt],val);
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) update(pos,val,l,mid,rt<<1);
    else update(pos,val,mid+1,r,rt<<1|1);
    T[rt]=max(T[rt<<1],T[rt<<1|1]);
}

ll query(int l,int r,int L,int R,int rt)
{
    if(l<=L && r>=R) return T[rt];
    int mid=(L+R)>>1;
    ll tot=0;
    if(l<=mid) tot=max(tot,query(l,r,L,mid,rt<<1));
    if(r>mid) tot=max(tot,query(l,r,mid+1,R,rt<<1|1));
    return tot;
}

int main()
{
    //freopen("a.txt","r",stdin);
    read(n);read(d);
    for(int i=1;i<=n;i++) 
    {
        ll a,b;
        read(a);read(b);
        int l=max(a-d,1ll),r=min(N-1ll,a+d);
        ll t=query(l,r,1,N-1,1)+b;
        ans=max(ans,t);
        update(a,t,1,N-1,1);
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(线段树/数状数组)