BZOJ 4341 [CF253 Printer] 解题报告

时间:2021-05-27 08:31:48

乍一看这个题好像可以二分优先度搞搞。。。

实际上能不能这么搞呢。。。?

我反正不会。。。

于是开始讲我的乱搞算法:

首先肯定要把任务按照优先度排序。

用一棵在线建点的线段树维护一个时刻是否在工作。

然后就依次插入任务,记为 i,具体而言就是二分其右端点,然后令这整个区间都变成 “工作” 的状态。

在 i 被插入之前,还要检验一下在当前情况那个神秘任务的右端点是不是题中所要求的那个。

如果是,并且 i-1 的优先度和 i 的优先度不相邻或者 i 就是最优先的任务,那么就令那个神秘任务的优先度为 i 的优先度+1。

然后把这个神秘任务插入,再来考虑任务 i。

这么写完之后发现超时了。一个点要跑 2.5s 左右。

实际上到了后面,超过 10^9 的时间是一段 1,然后才是 0。

所以这里我们只需维护这个分界点就可以了。

线段树的上界就从 10^15 变成了 10^9,比原来快了一倍。

于是就可以 AC 了。

 #include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = + ;
const int M = + ;
const int T = ; int n, root, tot, ans_p;
LL end, Tend = T, owari, Ans[N]; struct Segment_Tree
{
int l, r, sum;
}h[M]; struct Task
{
int s, t, p, id;
Task (int _s = , int _t = , int _p = , int _id = ) {s = _s, t = _t, p = _p, id = _id;}
bool operator < (const Task a) const
{
return p > a.p;
}
}P[N]; inline void Modify(int &x, int l, int r, int s, int t)
{
if (!x) x = ++ tot;
if (l == s && r == t) h[x].sum = r - l + ;
if (h[x].sum == r - l + ) return ;
LL mid = l + r >> ;
if (t <= mid) Modify(h[x].l, l, mid, s, t);
else if (s > mid) Modify(h[x].r, mid + , r, s, t);
else Modify(h[x].l, l, mid, s, mid), Modify(h[x].r, mid + , r, mid + , t);
h[x].sum = h[h[x].l].sum + h[h[x].r].sum;
} inline LL Query(int x, int l, int r, int s, int t)
{
if (!x) return ;
if (h[x].sum == r - l + ) return t - s + ;
if (l == s && r == t) return h[x].sum;
LL mid = l + r >> ;
if (t <= mid) return Query(h[x].l, l, mid, s, t);
else if (s > mid) return Query(h[x].r, mid + , r, s, t);
else return Query(h[x].l, l, mid, s, mid) + Query(h[x].r, mid + , r, mid + , t);
} inline LL Calc(Task x)
{
int need = x.t;
int blank = T - x.s + - Query(, , T, x.s, T);
if (blank < need) return need - blank + Tend;
int l = x.s, r = T;
while (l < r)
{
int mid = l + r >> ;
blank = mid - x.s + - Query(, , T, x.s, mid);
if (blank < need) l = mid + ;
else r = mid;
}
return l;
} int main()
{
scanf("%d", &n);
for (int i = ; i <= n; i ++)
{
int s, t, p;
scanf("%d%d%d", &s, &t, &p);
if (p == -) p = ;
P[i] = Task(s, t, p, i);
}
sort(P + , P + n + );
scanf("%lld", &end);
Ans[P[n].id] = end;
for (int i = ; i <= n; i ++)
{
if (ans_p) goto deal;
owari = Calc(P[n]);
if (owari + == end && (i == || P[i].p != P[i - ].p - ))
{
ans_p = P[i].p + ;
Modify(root, , T, P[n].s, owari < T ? owari : T);
Tend = Tend > owari ? Tend : owari;
} deal :;
if (i == n) continue ;
owari = Calc(P[i]);
Modify(root, , T, P[i].s, owari < T ? owari : T);
Tend = Tend > owari ? Tend : owari;
Ans[P[i].id] = owari + ;
}
printf("%d\n", ans_p);
for (int i = ; i <= n; i ++)
printf("%lld%c", Ans[i], i == n ? '\n' : ' '); return ;
}

4341_Gromah