1 条题解
-
0
自动搬运
来自洛谷,原作者为

lhm_
sjzez 的一名 OI 学生搬运于
2025-08-24 22:02:08,当前版本为作者最后更新于2020-05-01 00:12:37,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
首先考虑可以用二分答案来解决询问,可以二分一个长度,若在区间内包含了所有种的商店,那么这个就是合法的,可以通过二分来求其最小值。
对每个商店的存在时间转化为在时刻出现,在时刻消失,然后和询问一起离线按时间排序,就可以解决时间这一维的限制了。
然后考虑如何快速查询区间内是否包含所有的商店,和支持维护商店的出现消失。
对于这种区间数颜色的问题,可以对每个位置记录与其商店类型相同的上一个位置,发现一个位置上可能会有多个商店,那么这里的改为记录这些商店的到其各自商店类型相同的上一个位置的最小值。
是记录该位置商店类型相同的上一个位置,所以对于区间,如果从往后的所有位置的的最小值小于,那么说明至少有一种商店没在该区间出现。但是往后可能并不会包含所有种商店,因此加入哨兵商店来避免讨论,分别在最前面和最后面加入每种商店各一个。
然后就是如何支持维护,对于每个位置开一个维护该位置所有商店的对应其商店类型的前驱,中的最小值即为该位置的,然后用线段树动态开点来维护区间的最小值,这里其实就是在线段树的每个叶子节点开了一个来维护信息。
对于商店的出现消失维护,对每种商店类型开一个,维护该类型所有商店的出现位置,然后出现和消失只用解决对于该位置同类型的前驱和后继的影响就行,线段树单点修改即可实现。
若用线段树查询最小值来判定二分,复杂度是的,可以直接在线段树上二分位置,复杂度就是的了。
细节挺多,具体实现就看代码吧。
#include<bits/stdc++.h> #define maxn 900010 #define all 200000000 #define mid ((l+r)>>1) using namespace std; typedef multiset<int>::iterator muli; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } int n,k,q,tot,root,tree_cnt,num; int mi[maxn*20],ls[maxn*20],rs[maxn*20],ans[maxn]; multiset<int> p[maxn],s[maxn*20]; struct node { int pos,tim,id,opt; }t[maxn]; bool cmp(const node &a,const node &b) { if(a.tim==b.tim) return a.opt<b.opt; return a.tim<b.tim; } void modify(int l,int r,int pos,int v,int type,int &cur) { if(!cur) cur=++tree_cnt; if(l==r) { if(type) s[cur].insert(v); else s[cur].erase(s[cur].find(v)); if(!s[cur].empty()) mi[cur]=*s[cur].begin(); else mi[cur]=all; return; } if(pos<=mid) modify(l,mid,pos,v,type,ls[cur]); else modify(mid+1,r,pos,v,type,rs[cur]); mi[cur]=min(mi[ls[cur]],mi[rs[cur]]); } int query(int pos) { if(num<k) return -1; int l=1,r=all,cur=root,midmi,rmi=all; while(l<r) { midmi=min(rmi,mi[rs[cur]]); if(pos>mid||midmi<2*pos-mid) cur=rs[cur],l=mid+1; else rmi=midmi,cur=ls[cur],r=mid; } return l-pos; } int main() { read(n),read(k),read(q),mi[0]=all; for(int i=1;i<=k;++i) { p[i].insert(-all),p[i].insert(all); modify(1,all,all,-all,1,root); } for(int i=1;i<=n;++i) { int x,id,a,b; read(x),read(id),read(a),read(b); t[++tot]=(node){x,a,id,1}; t[++tot]=(node){x,b+1,id,0}; } for(int i=1;i<=q;++i) { int pos,tim; read(pos),read(tim); t[++tot]=(node){pos,tim,i,2}; } sort(t+1,t+tot+1,cmp); for(int i=1;i<=tot;++i) { int opt=t[i].opt,id=t[i].id,pos=t[i].pos; muli a,b; if(opt==0) { a=b=p[id].lower_bound(pos),a--,b++; modify(1,all,*b,pos,0,root); modify(1,all,*b,*a,1,root); modify(1,all,pos,*a,0,root); if(p[id].size()==3) num--; p[id].erase(p[id].find(pos)); } if(opt==1) { a=b=p[id].lower_bound(pos),a--; modify(1,all,*b,pos,1,root); modify(1,all,*b,*a,0,root); modify(1,all,pos,*a,1,root); if(p[id].size()==2) num++; p[id].insert(pos); } if(opt==2) ans[id]=query(pos); } for(int i=1;i<=q;++i) printf("%d\n",ans[i]); return 0; }
- 1
信息
- ID
- 3622
- 时间
- 5000ms
- 内存
- 1000MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者