LOJ#2585. 「APIO2018」新家 线段树二分+堆
自己想出来的,还是相当开心的(说实话这题也不难 QAQ......)
首先,那个时间限制非常好处理:离线然后拆成插入和删除就行.
对于每一种元素的每一个位置维护一个 $pre_{i}$ 表示上一次出现的位置.
假设我们查询的位置是 $pos$,我们二分答案 $mid$.
如果 $mid$ 合法,就要有 $x_{i} > pos+mid$ 且 $pre_{i}<pos-mid$.
显然,如果全扫一遍每一种元素的话显然会 TLE.
考虑维护以 $x_{i}$ 为下标,$pre_{i}$ 为权值的线段树.
对于每一个区间,维护其最小值(这个用 set 或可删除堆实现)
然后在线段树上二分就行了,判断 $mid$ 是否合法的话就是看右区间的堆顶是否合法.
只在叶节点开 multiset 就行了,时间复杂度是一个 log 的.
code:
#include <set> #include <ctime> #include <cstdio> #include <vector> #include <cstring> #include <algorithm> #define ll long long #define N 300008 #define pb push_back #define lson now<<1 #define rson now<<1|1 #define inf 1500000000 #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout) using namespace std; int A[N<<1],Ans[N]; int n,K,Q,inf1,inf2; struct data { int op,t,ty,x; data(int op=0,int t=0,int ty=0,int x=0):op(op),t(t),ty(ty),x(x){} bool operator<(const data b) const { return t<b.t; } }; vector<data>g; struct ques { int x,t,id; ques(int x=0,int t=0,int id=0):x(x),t(t),id(id){} bool operator<(const ques b) const { return t<b.t; } }arr[N]; int minv[N<<4]; multiset<int>col[N]; multiset<int>se[N<<4]; multiset<int>::iterator it; inline int minn(int x) { return se[x].size()?*se[x].begin():inf; } void update(int l,int r,int now,int p,int v,int op) { if(l==r) { if(op==1) se[now].insert(v); else se[now].erase(se[now].lower_bound(v)); minv[now]=minn(now); return; } int mid=(l+r)>>1; if(p<=mid) update(l,mid,lson,p,v,op); else update(mid+1,r,rson,p,v,op); minv[now]=min(minv[lson],minv[rson]); } int query(int l,int r,int now,int key) { if(l==r) return min(A[l]-key,key-minv[now]); int mid=(l+r)>>1; if(A[mid]-key<key-minv[rson]) return max(A[mid]-key,query(mid+1,r,rson,key)); else return max(key-minv[rson],query(l,mid,lson,key)); } int ask(int l,int r,int now,int p) { if(l==r) return minv[now]; int mid=(l+r)>>1; if(p<=mid) return ask(l,mid,lson,p); else return ask(mid+1,r,rson,p); } void build(int l,int r,int now) { minv[now]=inf; if(l==r) return; int mid=(l+r)>>1; build(l,mid,lson),build(mid+1,r,rson); } char *p1,*p2,buf[100000]; #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) int rd() { int x=0; char c; while(c<48) c=nc(); while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x; } int main() { // setIO("input"); int cn=0; n=rd(),K=rd(),Q=rd(); A[++cn]=inf,A[++cn]=-inf; for(int i=1;i<=n;++i) { int x=rd(),t=rd(),a=rd(),b=rd(); g.pb(data(1,a,t,x)),g.pb(data(-1,b+1,t,x)),A[++cn]=x; } for(int i=1;i<=Q;++i) arr[i].x=rd(),arr[i].t=rd(),arr[i].id=i,A[++cn]=arr[i].x; sort(A+1,A+1+cn); cn=unique(A+1,A+1+cn)-A-1; for(int i=1;i<=Q;++i) arr[i].x=lower_bound(A+1,A+1+cn,arr[i].x)-A; for(int i=0;i<g.size();++i) g[i].x=lower_bound(A+1,A+1+cn,g[i].x)-A; sort(arr+1,arr+1+Q); sort(g.begin(),g.end()); inf1=lower_bound(A+1,A+1+cn,-inf)-A; inf2=lower_bound(A+1,A+1+cn,inf)-A; for(int i=1;i<=K;++i) col[i].insert(inf1),col[i].insert(inf2); build(1,cn,1); for(int i=1;i<=K;++i) update(1,cn,1,inf2,-inf,1); for(int i=1,j=0;i<=Q;++i) { for(;j<g.size()&&g[j].t<=arr[i].t;++j) { if(g[j].op==-1) { int c=g[j].ty,pos=g[j].x,pr,nx; it=col[c].lower_bound(pos); it--,pr=(*it); it++,it++,nx=(*it); update(1,cn,1,pos,A[pr],-1); update(1,cn,1,nx,A[pos],-1); update(1,cn,1,nx,A[pr],1); col[c].erase(col[c].lower_bound(pos)); } else { int c=g[j].ty,pos=g[j].x,pr,nx; col[c].insert(pos); it=col[c].lower_bound(pos); it--,pr=(*it); it++,it++,nx=(*it); update(1,cn,1,nx,A[pr],-1); update(1,cn,1,pos,A[pr],1); update(1,cn,1,nx,A[pos],1); } } Ans[arr[i].id]=(ask(1,cn,1,inf2)==-inf?-1:query(1,cn,1,A[arr[i].x])); } for(int i=1;i<=Q;++i) printf("%d\n",Ans[i]); return 0; }