Live2D

[CTSC2015]日程管理

link

Solution

鉴于其于我的教育性意义,所以决定还是不放在寒假橄榄计划😢里面了。

我们首先考虑没有修改操作时候怎么做。发现可以套用拟阵模型。首先遗传性是肯定的,一个合法的方案集合其子集必然合法。然后我们需要考虑证明其拓展性,对于两个方案集合 \(A,B\),设 \(|A|<|B|\),需要判断是否存在 \(x\in B \backslash A\)\(A\cap \{x\}\) 也是合法集合。注意到最优情况下 \(A,B\) 都占用的都是时间的一个前缀,设 \(B_{|A|+1,...,|B|}\) 这一段为 \(S\),如果 \(S\not\subseteq A\),那么显然是合法的。否则,我们可以从 \(A\) 中属于 \(S\) 的元素中任取一个元素提到 \(S\) 中对应的位置,这样原位置就空出来了,然后就可以递归下去(指可以把空位即以后都删除当做 \(A\) 继续递归)。可以发现最后一定会合法。

所以我们的贪心策略就很显然了,我们按权值从大到小加入,然后每次判断能否加入即可。至于判断的话,判断条件即是 \(\forall i\in [1,T],\sum_{(t,p)} [t\le i] \le i\),这个可以用线段树维护每个 \(i\)\(i-\sum_{(t,p)} [t\le i]\)最小值,修改的话即是一个后缀 \(\pm 1\)

然后考虑实时维护,可以发现其实就跟最大生成树一个套路了。加入的时候先加入,如果合法则不管了。否则,我们找到线段树上 \(<0\) 的最小的位置 \(q\),然后把当前集合 \(t\in [1,q]\) 中最小的 \(p\) 删除即可。删除的时候也差不多,如果本来就不在最优集合里,则可以不管,否则先删除,然后找到线段树上 \(=0\) 的最大的位置 \(q\),则可以加入 \(t\in [q+1,T]\) 的最大的 \(p\)。可以看出删除一个,再补的话最多只会补一个,否则如果能加 \(2\) 个的话就会违反拓展性。

上面的步骤可以用两个线段树加可删堆/set维护,复杂度 \(\mathcal O(n\log n)\)

Code

#include <bits/stdc++.h>
using namespace std;

#define inf 0x3f3f3f3f3fll
#define Int register int
#define int long long
#define MAXN 300005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int T,n;

#define pii pair<int,int>
#define se second
#define fi first
struct Que{
	priority_queue <pii> q1,q2;
	void ins (pii it){q1.push (it);}
	void del (pii it){q2.push (it);}
	void pushit (){while (!q1.empty() && !q2.empty() && q1.top() == q2.top()) q1.pop (),q2.pop ();}
	pii Top (){pushit ();return q1.empty() ? make_pair(-inf,0ll) : q1.top();}
	bool Empty(){pushit ();return q1.empty();}
};

struct Seg{
	int tag[MAXN << 2],miv[MAXN << 2];
	void pushup (int x){miv[x] = min (miv[x << 1],miv[x << 1 | 1]);}
	void pushadd (int x,int v){miv[x] += v,tag[x] += v;}
	void pushdown (int x){pushadd (x << 1,tag[x]),pushadd (x << 1 | 1,tag[x]),tag[x] = 0;}
	void modify (int x,int l,int r,int ql,int qr,int v){
		if (l >= ql && r <= qr) return pushadd (x,v);
		int mid = l + r >> 1;pushdown (x);
		if (ql <= mid) modify (x << 1,l,mid,ql,qr,v);
		if (qr > mid) modify (x << 1 | 1,mid + 1,r,ql,qr,v);
		pushup (x);
	}
	int queryl (int x,int l,int r){
		if (l == r) return l;
		int mid = l + r >> 1;pushdown (x);
		if (miv[x << 1] == miv[x]) return queryl (x << 1,l,mid);
		else return queryl (x << 1 | 1,mid + 1,r);
	}
	int queryr (int x,int l,int r){
		if (l == r) return l;
		int mid = l + r >> 1;pushdown (x);
		if (miv[x << 1 | 1] == miv[x]) return queryr (x << 1 | 1,mid + 1,r);
		else return queryr (x << 1,l,mid);
	}
	void build (int x,int l,int r){
		miv[x] = l;
		if (l == r) return ;
		int mid = l + r >> 1;
		build (x << 1,l,mid),build (x << 1 | 1,mid + 1,r);
	}
	void ins (int t){modify (1,1,T,t,T,-1);}
	void del (int t){modify (1,1,T,t,T,1);}
}tr;

struct Segment{
	map <pii,int> mp;
	Que sT[MAXN];int mip[MAXN << 2],sum;
	void pushup (int x){mip[x] = sT[mip[x << 1]].Top() > sT[mip[x << 1 | 1]].Top() ? mip[x << 1] : mip[x << 1 | 1];}
	void ins (int x,int l,int r,int t,int p){
		if (l == r) return sT[t].ins ({p,t}),sum += p,void ();
		int mid = l + r >> 1;
		if (t <= mid) ins (x << 1,l,mid,t,p);
		else ins (x << 1 | 1,mid + 1,r,t,p);
		pushup (x);
	}
	void del (int x,int l,int r,int t,int p){
		if (l == r) return sT[t].del ({p,t}),sum -= p,void ();
		int mid = l + r >> 1;
		if (t <= mid) del (x << 1,l,mid,t,p);
		else del (x << 1 | 1,mid + 1,r,t,p);
		pushup (x); 
	}
	pii query (int x,int l,int r,int ql,int qr){
		if (l >= ql && r <= qr) return sT[mip[x]].Top();
		int mid = l + r >> 1;pii res = {-inf,0};
		if (ql <= mid) chkmax (res,query (x << 1,l,mid,ql,qr));
		if (qr > mid) chkmax (res,query (x << 1 | 1,mid + 1,r,ql,qr));
		return res;
	}
	void Ins (int t,int p){ins (1,1,T,t,p),mp[{t,p}] ++;}
	void Del (int t,int p){del (1,1,T,t,p),mp[{t,p}] --;}
	bool checkit (int t,int p){return mp[{t,p}];}
	void build (int x,int l,int r){
		if (l == r) return mip[x] = l,void ();
		int mid = l + r >> 1;
		build (x << 1,l,mid),build (x << 1 | 1,mid + 1,r),pushup (x);
	}
}T1,T2;

void addit (int t,int p){
	tr.ins (t),T1.Ins (t,-p);
	if (tr.miv[1] >= 0) return ;
	int pos = tr.queryl (1,1,T);pii it = T1.query (1,1,T,1,pos);
	T1.Del (it.se,it.fi),T2.Ins (it.se,-it.fi),tr.del (it.se);
}
void delit (int t,int p){
	if (T2.checkit (t,p)) return T2.Del (t,p);
	tr.del (t),T1.Del (t,-p); 
	int pos = tr.miv[1] > 0 ? 0 : tr.queryr (1,1,T);pii it = T2.query (1,1,T,pos + 1,T);
	if (it.fi == -inf) return ;
	T2.Del (it.se,it.fi),T1.Ins (it.se,-it.fi),tr.ins (it.se);
}

signed main(){
	read (T,n),tr.build (1,1,T),T1.build (1,1,T),T2.build (1,1,T);
	while (n --> 0){
		char str[10] = {};scanf ("%s",str + 1);int t,p;read (t,p);
		if (str[1] == 'A') addit (t,p);
		else delit (t,p);
		write (-T1.sum),putchar ('\n');
	} 
	return 0;
}
posted @ 2023-01-30 22:11  Dark_Romance  阅读(30)  评论(0编辑  收藏  举报