[ABC363G] Dynamic Scheduling 与 P4511 [CTSC2015] 日程管理

嚴華  金牌会员 | 2024-7-26 09:07:05 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 915|帖子 915|积分 2745

思路:

对于插入操作,设插入 \(\{t,p\}\):

  • 若当前 \(1 \sim t\) 有空位,那么就放进去。
  • 否则,\(1 \sim t\) 是被塞满了的:

    • 起首容易想到的是找到 \(1 \sim t\) 中贡献最小的那个工作,若贡献比 \(p\) 还小,可以与之更换掉。
    • 但是假了,考虑这样一种情况:在 \(1 \sim t\) 外有一个更小的值,可以跟 \(1 \sim t\) 中的某个工作换一个位置,然后再将这个更换过来的工作更换掉,这样无疑是更优的。
    • 考虑如何快速维护这个东西,使用两棵线段树:

      • 第一棵线段树维护所有停止时间在区间 \([l,r]\) 的时刻完成的任务的停止时间的最大值。
      • 第二棵线段树维护所有停止时间在区间 \([l,r]\) 的时刻完成的任务的贡献的最小值。

    • 我们需要找到经过更换能更换到的最远时刻:

      • 令 \(A_{fi}\) 表示当前 \(1 \sim t\) 中停止时间最晚的时间,\(A_{se}\) 为 \(1 \sim t\) 中停止时间最晚的工作完成的时刻。
      • 令 \(B_{fi}\) 表示当前 \(1 \sim A_{fi}\) 中停止时间最晚的时间,\(B_{se}\) 为 \(1 \sim A_{fi}\) 中停止时间最晚的工作完成的时刻。
      • 那么若 \(A_{fi} < B_{fi}\):

        • 说明可以将 \(A_{se}\) 与 \(B_{se}\) 时刻的工作调换一下。
        • 因为可以使得 \(1 \sim t\) 内的工作的最晚停止时刻更长。

      • 然后一直重复交换操作,直到不满足 \(A_{fi} < B_{fi}\) 为止。

    • 经过上述的操作,\(A_{fi}\) 达到了最大值;令 \(C_{fi}\) 表示当前 \(1 \sim A_{fi}\) 中工作贡献的最小值,\(C_{se}\) 表示完成最小贡献的工作所处的时刻。
    • 若 \(C_{se} > t\),可以将 \(A_{se}\) 与 \(C_{se}\) 交换一下。
    • 此时的 \(C_{fi}\) 就是可以找到更换的最小值,若 \(p > C_{fi}\),则可以更换。

对于删除操作:

  • 若删除的工作我们选择完成了,设在 \(t\) 时刻完成:

    • 那么容易想到,可以找到停止时间在 \(t \sim T\) 中贡献最大且没有完成的工作,顶替上来即可。
    • 但是也假了,考虑这样一种情况,可以将 \(t\) 与 \(1 \sim t-1\) 时刻的某个工作 \(t'\) 交换,使得 \(t' \sim T\) 的最大贡献在 \(t' \sim t\) 中,则只看 \(t \sim T\) 是不优的。
    • 我们需要将 \(t\) 换到尽可能前面去,考虑二分:

      • 若 \(1 \sim mid\) 中停止时间最晚的时间是大于等于 \(t\) 的,说明 \(1 \sim mid\) 中有一个位置可以与 \(t\) 换,令 \(r=mid-1\);否则 \(l=mid+1\)。
      • 设当前找到的最靠前的时刻为 \(t'\),令 \(t \gets t'\),然后再在 \(1 \sim t\) 的范围内二分。
      • 重复二分直到找不到 \(1 \sim t-1\) 范围内的点与 \(t\) 交换,即不存在 \(t'\)。

    • 此时我们得到了最小的 \(t\),找 \(t \sim T\) 内贡献最大且没有完成的工作顶替即可。
    • 可以使用第三棵线段树:维护所有停止时间在区间 \([l,r]\) 的时刻未完成的任务的贡献的最大值。

  • 若并没有完成该工作,则直接在第三棵线段树上将这个点的贡献消除即可。
第三棵线段树需要支持一个撤销操作,因为可能有完全一模一样的工作,需要在叶子节点处使用 multiset 维护最大值。
时间复杂度为 \(O(N \log^3 N)\)。
该做法码量和常数较大,审慎使用。
完整代码:

[code]#include#define Add(x,y) (x+y>=mod)?(x+y-mod)x+y)#define lowbit(x) x&(-x)#define pi pair#define pii pair#define iip pair#define ppii pair#define fi first#define se second#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x#define Full(a) memset(a,0,sizeof(a))#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);using namespace std;typedef double db;typedef unsigned long long ull;typedef long long ll;bool Begin;const ll N=1e5+10,INF=1e18;inline ll read(){    ll x=0,f=1;    char c=getchar();    while(c'9'){        if(c=='-')          f=-1;        c=getchar();    }    while(c>='0'&&c
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

嚴華

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表