Live2D

[CTSC2015]日程管理

link

Solution#

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

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

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

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

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

Code#

Copy
#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 @   Dark_Romance  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
CONTENTS