思路:
對於插入操作,設插入 \(\{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;
}
*/