P12247 跳舞机(平衡树+动态规划)

P12247 跳舞机(平衡树+动态规划)

题目传送门

题意简介

\(m\) 分钟内有 \(n\) 个人参与游戏,在 \([L_i,R_i]\) 时间内每花费 \(k\) 分钟可获得 \(w_i\) 的权值,同一时间仅有1人可参与游戏,求结束时最大权值和

思路

考虑 \(dp_i\) 表示前 \(i\) 分钟可以获得的最大兴奋度,分为两种情况:

  • \(i\) 分钟没有人参与游戏, \(dp_i\) = \(dp_{i-1}\)
  • \(i\) 分钟有人刚结束游戏, \(dp_i\) = \(dp_{i-k}\) \(+\) \(w\),其中 \(w\) 是有可能在该时刻结束游戏的人中权值最大的

第一种情况非常简单,对于第二种情况,难点在于如何快速求解哪些人可能在该时刻结束游戏并且查找其中权值最大者,使用平衡树来维护,将过时的人删除,并完成最值查找

Code

#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int M=2e6+5;
struct AVL_Tree
{
    struct node
    {
        int lft,rgt,val,height,cnt,siz;
    }Tree[M];
    int point=0;
    int NewNode(int val)
    {
        Tree[++point]={0,0,val,1,1,1};
        return point;
    }
    int GetBalance(int k)
    {
        return Tree[Tree[k].lft].height-Tree[Tree[k].rgt].height;
    }
    void Pushup(int k)
    {
        Tree[k].height=max(Tree[Tree[k].lft].height,Tree[Tree[k].rgt].height)+1;
        Tree[k].siz=Tree[Tree[k].lft].siz+Tree[Tree[k].rgt].siz+Tree[k].cnt;
    }
    int L(int k)
    {
        int R=Tree[k].rgt;
        Tree[k].rgt=Tree[R].lft,Tree[R].lft=k;
        Pushup(k),Pushup(R);
        return R;
    }
    int R(int k)
    {
        int L=Tree[k].lft;
        Tree[k].lft=Tree[L].rgt,Tree[L].rgt=k;
        Pushup(k),Pushup(L);
        return L;
    }
    int Balance(int k)
    {
        int BalanceFactor=GetBalance(k);
        if(BalanceFactor>1)
        {
            if(GetBalance(Tree[k].lft)<0)
                Tree[k].lft=L(Tree[k].lft);
            return R(k);
        }
        if(BalanceFactor<-1)
        {
            if(GetBalance(Tree[k].rgt)>0)
                Tree[k].rgt=R(Tree[k].rgt);
            return L(k);
        }
        return k;
    }
    int FindMin(int k)
    {
        while(Tree[k].lft) k=Tree[k].lft;
        return k;
    }
    int FindMax(int k)
    {
        while(Tree[k].rgt) k=Tree[k].rgt;
        return k;
    }
    int Insert(int k,int val)
    {
        if(!k) return NewNode(val);
        if(Tree[k].val>val)
            Tree[k].lft=Insert(Tree[k].lft,val);
        else if(Tree[k].val<val)
            Tree[k].rgt=Insert(Tree[k].rgt,val);
        else
        {
            Tree[k].cnt++;
            Tree[k].siz++;
            return k;
        }
        Pushup(k);
        return Balance(k);
    }
    int Delete(int k,int val)
    {
        if(!k) return 0;
        if(Tree[k].val>val)
            Tree[k].lft=Delete(Tree[k].lft,val);
        else if(Tree[k].val<val)
            Tree[k].rgt=Delete(Tree[k].rgt,val);
        else
        {
            if(Tree[k].cnt>1)
            {
                Tree[k].cnt--;
                Tree[k].siz--;
                return k;
            }
            if((!Tree[k].lft)||(!Tree[k].rgt))
                return Tree[k].lft|Tree[k].rgt;
            int MinNode=FindMin(Tree[k].rgt);
            Tree[k].val=Tree[MinNode].val;
            Tree[k].cnt=1;
            Tree[k].rgt=Delete(Tree[k].rgt,Tree[MinNode].val);
        }
        Pushup(k);
        return Balance(k);
    }
}Tree;
int n,m,k,root;
long long dp[M];
vector<pair<int,int>>a[M];
int main()
{
    IOS;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
    {
        int l,r,w;
        cin>>l>>r>>w;
        if(r-l+1<k) continue;
        a[l+k-1].push_back({w,1});
        a[r+1].push_back({w,-1});//按时间为下标维护每一个人存在的时间段
    }
    for(int i=1;i<=m;i++)
    {
        for(auto v:a[i])
        {
            if(v.second==1)
                root=Tree.Insert(root,v.first);
            else//将过时的人删除
                root=Tree.Delete(root,v.first);
        }
        if(i<k) dp[i]=dp[i-1];
        else dp[i]=max(dp[i-1],dp[i-k]+Tree.Tree[Tree.FindMax(root)].val);
    }
    cout<<dp[m]<<'\n';
    return 0;
}

完结撒花~

posted @ 2025-07-30 15:04  FallingGardenia  阅读(8)  评论(0)    收藏  举报