思路:

对于插入操作,设插入 \(\{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. c#获取开机时间

    public static DateTime OpenCom() { TimeSpan t = TimeSpan.FromMilliseconds(System.Environment.TickCou ...

  2. C# wpf 实现截屏框实时截屏功能

    wpf截屏系列第一章 使用GDI+实现截屏第二章 使用DockPanel制作截屏框第三章 实现截屏框实时截屏(本章)第四章 使用ffmpeg命令行实现录屏 文章目录wpf截屏系列前言一.实现步骤1.获 ...

  3. Yii AR事务操作

    Yii Ar事务操作,示例代码如下: $model=Post::model(); $transaction=$model->dbConnection->beginTransaction() ...

  4. JS中BOM事件,JS样式特效,表格对象和表单操作

    DOM事件 1.DOM中的事件可以分为两类 1.浏览器行为 如:文档加载完成,图片加载完成 2.用户行为 如:输入框输入数据,点击按钮 (2).常见的DOM事件 onload 浏览器已完成页面的加载 ...

  5. java中判断String类型为空和null的方法

    1.判断一个String类型的变量是否为空(即长度为0)或者为null 在Java中,判断一个String类型的变量是否为空(即长度为0)或者为null,通常需要使用两个条件语句来进行检查.这是因为n ...

  6. 搭建单机版伪分布式Hadoop+Scala+spark

    搭建单机版伪分布式Hadoop+Scala+spark 修改ip [root@master ~]# nmcli connection add ifname ens32 con-name ens32 a ...

  7. css圆圈慢慢放大

    <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8 ...

  8. 铭瑄B760 ITX 无法睿频 无法跑满

    铭瑄B760 ITX 无法睿频 无法跑满 状况: 铭瑄B760 ITX + 12600K,跑分时,大核最高 3.7GHz,电压也不到1V.CPU-Z 跑分才600. 解决方法: 1.关机. 2.长按 ...

  9. 使用Git命令从本地上传到码云

    Gitee创建仓库内没有内容 本地: 初始化Git仓库:git init 提交文件到暂存区:git add . //. 表示提交所有文件 提交文件到工作区:git commit -m "此次 ...

  10. PasteSpider的集群组件PasteCluster(让你的项目快速支持集群模式)的思路及实现(含源码)

    PasteSpider是什么? 一款使用.net编写的开源的Linux容器部署助手,支持一键发布,平滑升级,自动伸缩, Key-Value配置,项目网关,环境隔离,运行报表,差量升级,私有仓库,集群部 ...