题解:P3968 [TJOI2014] 电源插排
题意
维护一个
- 单点将
修改为 。 - 查询区间中
的个数。 - 查询最长且最靠右的连续
段的靠右的中点,并将其改为 。
分析
第一个操作和第二个操作显然使用动态开点线段树维护。
我们只需要解决第三个操作。
我们用平衡树存储连续的
维护两棵平衡树,一棵按区间的左端点从小到大排序,另一棵以区间长度为第一关键字,左端点为第二关键字从大到小排序。
询问的时候只需要在第二棵平衡树中取出其最大的元素。
考虑修改操作带来的影响。
单点修改为
分类讨论处理一下段的分裂情况。
单点修改为
在第一棵树上二分找出插入点前后的连续段,同样分类讨论一下段的合并情况。
时间复杂度
发现平衡树只需要支持查前驱后继,所以可以使用 set
实现。
可以向 set
中加入两个哨兵区间
Code
#include<bits/stdc++.h> using namespace std; struct SegT { struct node { uint32_t sum; node *lc, *rc; node() {lc=rc=0; sum=0;} }*rt; #define mid ((l+r)>>1) #define lson x->lc, l, mid #define rson x->rc, mid+1, r void modify(node *&x, int l, int r, int p, int v) { if(!x) x=new node; x->sum+=v; if(l==r) return; if(p<=mid) modify(lson, p, v); if(p>mid) modify(rson, p, v); } uint32_t query(node *x, int l, int r, int L, int R) { if(!x) return 0; if(L<=l&&r<=R) return x->sum; uint32_t ret=0; if(L<=mid) ret+=query(lson, L, R); if(R>mid) ret+=query(rson, L, R); return ret; } }tr; struct itv { int l, r; int pos() {return (l+r+1)>>1;} itv(int L, int R) {l=L, r=R;} }; #define len(x) (x.r-x.l+1) struct cmp1{bool operator()(itv a, itv b)const{return a.l<b.l;}}; struct cmp2{bool operator()(itv a, itv b)const{return len(a)==len(b)?a.l>b.l:len(a)>len(b);}}; set<itv, cmp1> s1; set<itv, cmp2> s2; map<int, int> pos; void emplace(int x, int y) {s1.emplace(x, y), s2.emplace(x, y);} void emplace(itv &x) {s1.emplace(x), s2.emplace(x);} void erase(itv &x) {s1.erase(x), s2.erase(x);} int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n, q, l, r, k; cin>>n>>q; emplace(1, n); emplace(-1, -2); emplace(n+2, n+1); while(q--) { cin>>k; if(!k) cin>>l>>r, cout<<tr.query(tr.rt, 1, n, l, r)<<'\n'; else { if(!pos[k]) { auto seg=*s2.begin(); erase(seg); int p=seg.pos(); pos[k]=p; tr.modify(tr.rt, 1, n, p, 1); if(p!=seg.l) emplace(seg.l, p-1); if(p!=seg.r) emplace(p+1, seg.r); } else { int p=pos[k]; pos[k]=0; tr.modify(tr.rt, 1, n, p, -1); auto it=s1.lower_bound({p, 0}); auto seg2=*it, seg1=*--it; if(seg1.r==p-1&&seg2.l==p+1) erase(seg1), erase(seg2), emplace(seg1.l, seg2.r); else if(seg1.r==p-1) erase(seg1), emplace(seg1.l, p); else if(seg2.l==p+1) erase(seg2), emplace(p, seg2.r); else emplace(p, p); } } } }
本文作者:redacted-area
本文链接:https://www.cnblogs.com/redacted-area/p/18405331
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步