思路:

对于插入操作,设插入 \(\{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)\)。

该做法码量和常数较大,谨慎使用。

完整代码:

#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#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<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
// T1 维护 1 ~ x 时刻中完成的任务的截止时间的最大值
// T2 维护 1 ~ x 时刻中完成的任务的得分的最小值
// T3 维护 1 ~ x 时刻中未完成的任务的得分的最大值
ll n,q,c,x,y,z,l,r,t,ans;
ll a[N],b[N],X[N],Y[N],Z[N];
map<pi,ll> cnt;
map<iip,ll> F;
class Tree1{
public:
pi H[N<<2]; //{最大值,位置}
pi add(pi a,pi b){
if(a.fi>b.fi)
return a;
return b;
}
void pushup(ll k){
H[k]=add(H[k<<1],H[k<<1|1]);
}
void build(ll k,ll l,ll r){
if(l==r){
H[k].fi=0;
H[k].se=l;
return ;
}
ll mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
void update(ll k,ll l,ll r,ll i,ll v){
if(l==i&&i==r){
H[k].fi=v;
return ;
}
ll mid=(l+r)>>1;
if(i<=mid)
update(k<<1,l,mid,i,v);
else
update(k<<1|1,mid+1,r,i,v);
pushup(k);
}
void del(ll k,ll l,ll r,ll i){
if(l==i&&i==r){
H[k].fi=0;
return ;
}
ll mid=(l+r)>>1;
if(i<=mid)
del(k<<1,l,mid,i);
else
del(k<<1|1,mid+1,r,i);
pushup(k);
}
pi query(ll k,ll l,ll r,ll L,ll R){
if(L>R)
return {-INF,0};
if(l==L&&R==r)
return H[k];
ll mid=(l+r)>>1;
if(R<=mid)
return query(k<<1,l,mid,L,R);
else if(L>mid)
return query(k<<1|1,mid+1,r,L,R);
else
return add(query(k<<1,l,mid,L,mid),query(k<<1|1,mid+1,r,mid+1,R));
}
void Swap(ll x,ll y){
ll xx=query(1,1,n,x,x).fi;
ll yy=query(1,1,n,y,y).fi;
update(1,1,n,x,yy);
update(1,1,n,y,xx);
}
}T1;
class Tree2{
public:
pi H[N<<2]; //{最小值,位置}
pi add(pi a,pi b){
if(a.fi<b.fi)
return a;
return b;
}
void pushup(ll k){
H[k]=add(H[k<<1],H[k<<1|1]);
}
void build(ll k,ll l,ll r){
if(l==r){
H[k].fi=0;
H[k].se=l;
X[l]=Y[l]=Z[l]=0;
return ;
}
ll mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
void update(ll k,ll l,ll r,ll i,ll x,ll y,ll c){
if(l==i&&i==r){
H[k].fi=y;
X[i]=x,Y[i]=y,Z[i]=c;
F[{{x,y},c}]=i;
return ;
}
ll mid=(l+r)>>1;
if(i<=mid)
update(k<<1,l,mid,i,x,y,c);
else
update(k<<1|1,mid+1,r,i,x,y,c);
pushup(k);
}
void del(ll k,ll l,ll r,ll i){
if(l==i&&i==r){
H[k].fi=0;
F[{{X[i],Y[i]},Z[i]}]=0;
X[i]=Y[i]=Z[i]=0;
return ;
}
ll mid=(l+r)>>1;
if(i<=mid)
del(k<<1,l,mid,i);
else
del(k<<1|1,mid+1,r,i);
pushup(k);
}
pi query(ll k,ll l,ll r,ll L,ll R){
if(L>R)
return {INF,0};
if(l==L&&R==r)
return H[k];
ll mid=(l+r)>>1;
if(R<=mid)
return query(k<<1,l,mid,L,R);
else if(L>mid)
return query(k<<1|1,mid+1,r,L,R);
else
return add(query(k<<1,l,mid,L,mid),query(k<<1|1,mid+1,r,mid+1,R));
}
void Swap(ll x,ll y){
ll xx1=X[x],yy1=Y[x],cc1=Z[x],xx2=X[y],yy2=Y[y],cc2=Z[y];
update(1,1,n,x,xx2,yy2,cc2);
update(1,1,n,y,xx1,yy1,cc1);
}
}T2;
class Tree3{
public:
ll id[N];
multiset<pii> S[N];
iip H[N<<2]; // {{x,y},c}
iip add(iip a,iip b){
if(a.fi.se>b.fi.se)
return a;
return b;
}
void pushup(ll k){
H[k]=add(H[k<<1],H[k<<1|1]);
}
void update(ll k,ll l,ll r,ll x,ll y,ll c){
if(l==x&&x==r){
S[x].insert({-y,{-x,-c}});
auto t=(*S[x].begin());
H[k]={{-t.se.fi,-t.fi},-t.se.se};
return ;
}
ll mid=(l+r)>>1;
if(x<=mid)
update(k<<1,l,mid,x,y,c);
else
update(k<<1|1,mid+1,r,x,y,c);
pushup(k);
}
void del(ll k,ll l,ll r,ll x,ll y,ll c){
if(l==x&&x==r){
S[x].erase({-y,{-x,-c}});
auto t=(*S[x].begin());
H[k]={{-t.se.fi,-t.fi},-t.se.se};
return ;
}
ll mid=(l+r)>>1;
if(x<=mid)
del(k<<1,l,mid,x,y,c);
else
del(k<<1|1,mid+1,r,x,y,c);
pushup(k);
}
iip query(ll k,ll l,ll r,ll L,ll R){
if(l==L&&R==r)
return H[k];
ll mid=(l+r)>>1;
if(R<=mid)
return query(k<<1,l,mid,L,R);
else if(L>mid)
return query(k<<1|1,mid+1,r,L,R);
else
return add(query(k<<1,l,mid,L,mid),query(k<<1|1,mid+1,r,mid+1,R));
}
}T3;
void insert(ll x,ll y){
c=++cnt[{x,y}];
pi A,B;
pi C;
while(1){
A=T1.query(1,1,n,1,x);
B=T1.query(1,1,n,1,A.fi);
if(A.fi<B.fi){
T1.Swap(A.se,B.se);
T2.Swap(A.se,B.se);
}
else
break;
}
A=T1.query(1,1,n,1,x);
C=T2.query(1,1,n,1,A.fi);
if(C.se>x){
T1.Swap(A.se,C.se);
T2.Swap(A.se,C.se);
}
C=T2.query(1,1,n,1,x);
if(C.fi<y){
ans+=y-C.fi;
if(C.fi){
T3.update(1,1,n,X[C.se],Y[C.se],Z[C.se]);
T1.del(1,1,n,C.se);
T2.del(1,1,n,C.se);
}
T1.update(1,1,n,C.se,x);
T2.update(1,1,n,C.se,x,y,c);
}
else
T3.update(1,1,n,x,y,c);
}
void del(ll x,ll y){
c=cnt[{x,y}]--;
if(F[{{x,y},c}]){
ans-=y;
while(1){
z=F[{{x,y},c}];
l=1,r=z-1,t=-1;
while(l<=r){
ll mid=(l+r)>>1;
if(T1.query(1,1,n,1,mid).fi>=z){
t=mid;
r=mid-1;
}
else
l=mid+1;
}
if(t==-1)
break;
T1.Swap(t,z);
T2.Swap(t,z);
}
z=F[{{x,y},c}];
T1.del(1,1,n,z);
T2.del(1,1,n,z);
iip A=T3.query(1,1,n,z,n);
if(A.se){
ans+=A.fi.se;
T1.update(1,1,n,z,A.fi.fi);
T2.update(1,1,n,z,A.fi.fi,A.fi.se,A.se);
T3.del(1,1,n,A.fi.fi,A.fi.se,A.se);
}
}
else
T3.del(1,1,n,x,y,c);
}
bool End;
/*[ABC363G] Dynamic Scheduling
int main(){
n=read(),q=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++)
b[i]=read();
T1.build(1,1,n);
T2.build(1,1,n);
for(int i=1;i<=n;i++)
insert(a[i],b[i]);
// write(ans);
// putchar('\n');
while(q--){
x=read();
del(a[x],b[x]);
a[x]=read(),b[x]=read();
insert(a[x],b[x]);
write(ans);
putchar('\n');
}
cerr<<'\n'<<abs(&Begin-&End)/1048576<<"MB";
return 0;
}*/
/*P4511 [CTSC2015] 日程管理
int main(){
n=read(),q=read();
T1.build(1,1,n);
T2.build(1,1,n);
while(q--){
cin>>op;
x=read(),y=read();
if(op[0]=='A')
insert(x,y);
else
del(x,y);
write(ans);
putchar('\n');
}
return 0;
}
*/

[ABC363G] Dynamic Scheduling 与 P4511 [CTSC2015] 日程管理的更多相关文章

  1. jquery.fullCalendar官方文档翻译(一款小巧好用的日程管理日历, 可集成Google Calendar)

    1. 使用方式, 引入相关js, css后, $(‘#div_name’).fullCalendar({//options});  接受的是一个option对象 2. 普通属性 2.1. year, ...

  2. 日程管理控件 glDatePicker

    之前接触过一款日程管理控件,叫 FullCalendar,功能很强大,会列出每天的事项,可选择编辑并且可以定制自己的日历,然而,有时候,我们的网页上只需要一个简单的日历,迷你但实用,有日程安排的日期高 ...

  3. Web日程管理FullCalendar

    fullcalendar是一款jQuery日程管理控件,提供了丰富的属性设置和方法调用,官网下载地址http://fullcalendar.io/download,眼下最新版本号是2.3.2. 仅仅要 ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(86)-日程管理-fullcalendar插件用法

    前言 本文分享fullcalendar用法,最后面提供代码下载 说到日程管理,基于JQuery的插件FullCalendar当之无愧,完整的API稳定和调用方式,非常易于扩展!可以用于系统的个人历程管 ...

  5. 日程管理 FullCalendar

    日程管理,采用著名组件FullCalendar日历插件实现FullCalendar提供了丰富的属性设置和方法调用,开发者可以根据FullCalendar提供的API快速完成一个日历日程的开发1.实现按 ...

  6. RDIFramework.NET V3.3 Web版新增日程管理功能模块

    功能描述 在RDIFramework.NET V3.3 Web版本我们新增了日程管理.基于月.周.日的日历视图,把安排到每一天的具体时间点,让每一天的时间都充分利用:甚至您也可以把个人非工作事项也安排 ...

  7. RDIFramework.NET V3.3 WinForm版新增日程管理功能模块

    功能描述 日程管理基于月.周.日的日历视图,把安排到每一天的具体时间点,让每一天的时间都充分利用:甚至您也可以把个人非工作事项也安排进来,完全是属于自己的全时间管理.就是将每天的工作和事务安排在日期中 ...

  8. fullcalendar插件日程管理

    日程管理-fullcalendar插件用法   前言 本文分享fullcalendar用法,最后面提供代码下载 说到日程管理,基于JQuery的插件FullCalendar当之无愧,完整的API稳定和 ...

  9. DevExpress XtraScheduler日程管理控件应用实例(2)-- 深入理解数据存储

    DevExpress年终击穿底价,单套授权低至67折!查看详情>>> 在上篇随笔<DevExpress XtraScheduler日程管理控件应用实例(1)-- 基本使用> ...

  10. [Asp.net]Calendar+JqueryUi实现日程管理(右键菜单,添加,编辑,删除,源码)

    引言 出差终于回来了,这篇文章算是这个月的博客的开篇吧. 上篇文章:[Asp.net]Calendar+JqueryUi实现日程管理——添加日程 上篇文章主要贴了一些该项目的界面,这里面,将主要代码也 ...

随机推荐

  1. Bi-encoder vs Cross encoder?

    本文永久地址:https://wanger-sjtu.github.io/encoder-cross-bi/ Bi-encoder和Cross-encoder是在自然语言理解任务模型的两种不同方法,在 ...

  2. vue基础使用

    传统dom操作 使用js或jquery库对html页面结构中的指定的区域输出数据 使用vue实现 在html页面中使用好vue需要完成如下步骤即可 引入vue.js文件 定义给vue.js管理的dom ...

  3. The model backing the 'MainDbContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).

    The model backing the 'MainDbContext' context has changed since the database was created. Consider u ...

  4. C#.NET 保存图片时System.Runtime.InteropServices.ExternalException:“GDI+ 中发生一般性错误。”

    System.Runtime.InteropServices.ExternalException:"GDI+ 中发生一般性错误." 原因:文件夹不存在. 解决方法: if (!Di ...

  5. Java对象转Map<String,String>

    Java对象转Map<String,String> import org.springframework.beans.BeanUtils; import org.springframewo ...

  6. 制作tomcat镜像

    本篇文章介绍用Dockerfile的方式构建Tomcat镜像,请保证安装了Docker环境. 首先创建/opt/tomcat目录,后续步骤都在该目录下进行操作. 准备好Jdk和Tomcat安装文件,放 ...

  7. Postman 的 Basic Auth 如何通过 Feign 实现

    Postman 的 Basic Auth: 分析 根据以上图片分析: Postman 的 Authorization 实际为: header 中添加 Authorization: ******* ** ...

  8. 配置 Nginx + PHP(FastCGI/FPM)

    有关概念 Nginx是什么 Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器. Php-fpm是什么 1.c ...

  9. 对linux的理解--个人理解

    linux系统中的命令我觉得可以和windows上的点点点,如文件的查找,文件的新建.删除,用户的添加.删除等来对比理解.一个是点点点,一个是用命令来完成. --------------------- ...

  10. python 转换PDF 到 EPS

    from win32com.client.dynamic import ERRORS_BAD_CONTEXT as ebc from win32com.client import DispatchEx ...