[APIO2018] New Home 新家
Solution
对于时间轴我们直接离散化+扫描线,维护每一个商店的加入和删除。
对于询问(x,t)(x,t)(x,t),不好直接回答,这里的关键一步是:我们要求的是kkk种商店最小距离的最大值,于是考虑二分答案。二分一个最大值midmidmid,那么kkk种商店必须都在[x−mid,x+mid][x-mid,x+mid][x−mid,x+mid]出现过。我们考虑对于每一个商店维护和它类型相同的商店的前驱。那么[x−mid,x+mid][x-mid,x+mid][x−mid,x+mid]的条件就转化为了(x+mid,∞)(x+mid,\infty)(x+mid,∞)中的商店的前驱都不小于x−midx-midx−mid(注意−1-1−1的特殊情况)。
于是我们用一个setsetset维护每种商店的序列,用线段树维护后缀最小值即可。
时间复杂度O(nlgn⋅lgT)O(nlgn\cdot lgT)O(nlgn⋅lgT)。
Details
具体实现时有一些细节:
- 我们把每一种商店的第一个的前驱设为000。
- 每种商店的最后加一个∞\infty∞以简化−1-1−1的特判,具体可见代码。
- 可能会出现类型坐标时间都相同的商店,因此我们要在线段树每个位置维护一个multisetmultisetmultiset表示该坐标的最小值,而不能直接修改一个坐标的最小值。维护每个类型的setsetset也要是multisetmultisetmultiset
- 因为怕麻烦,我直接用的是动态开点线段树,跑得也挺轻松的。
Code
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se secondusing namespace std;template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=600005;
const int MX=1e8+300000;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f;
}
multiset<int> V[MAXN],Set[MAXN];
int nodenum=1,mn[MAXN*30],ls[MAXN*30],rs[MAXN*30],Ans[MAXN],id[MAXN*30],ID=0;
struct Cnode{ int t,x,y; } C[MAXN<<1],Q[MAXN];
void up(int x)
{mn[x]=INF;if (ls[x]) upmin(mn[x],mn[ls[x]]);if (rs[x]) upmin(mn[x],mn[rs[x]]);
}
int query(int x,int l,int r,int L,int R)
{if (!x) return INF;if (l>=L&&r<=R) return mn[x];int mid=(l+r)>>1;if (R<=mid) return query(ls[x],l,mid,L,R);else if (L>mid) return query(rs[x],mid+1,r,L,R);else return min(query(ls[x],l,mid,L,mid),query(rs[x],mid+1,r,mid+1,R));
}
int update(int x,int l,int r,int y,int z)
{if (!x) x=++nodenum;if (l==r) { id[x]=(id[x]?id[x]:++ID),V[id[x]].insert(z),mn[x]=*V[id[x]].begin(); return x; }int mid=(l+r)>>1;if (y<=mid) ls[x]=update(ls[x],l,mid,y,z);else rs[x]=update(rs[x],mid+1,r,y,z);up(x);return x;
}
void clear(int x,int l,int r,int y,int z)
{if (l==r) { V[id[x]].erase(V[id[x]].find(z)); mn[x]=(V[id[x]].size()?*V[id[x]].begin():INF); return; }int mid=(l+r)>>1;if (y<=mid) clear(ls[x],l,mid,y,z);else clear(rs[x],mid+1,r,y,z);up(x);
}int check(int x,int l) { return query(1,1,MX,min(x,(int)1e8+1),MX)>=max(l,1); }
signed main()
{int n=read(),k=read(),q=read(),num=0;for (int i=1;i<=n;i++){int x=read(),y=read(),a=read(),b=read();C[++num]=(Cnode){a,x,y},C[++num]=(Cnode){b+1,x,-y};}for (int i=1,x,y;i<=q;i++) x=read(),y=read(),Q[i]=(Cnode){y,x,i};sort(C+1,C+num+1,[&](Cnode a,Cnode b){ return (a.t<b.t)||(a.t==b.t&&a.x>b.x); });sort(Q+1,Q+q+1,[&](Cnode a,Cnode b){ return a.t<b.t; });for (int i=1;i<=k;i++) Set[i].insert(1e8+i),update(1,1,MX,1e8+i,0);C[num+1].t=INF;int nw=1;while (nw<=q&&Q[nw].t<C[1].t) Ans[Q[nw].y]=-1,nw++;for (int i=1;i<=num;i++){if (C[i].y>0){int t=C[i].y;Set[t].insert(C[i].x);multiset<int>::iterator it=Set[t].find(C[i].x),pre=it,nxt=it;update(1,1,MX,*(++nxt),*it);if (pre!=Set[t].begin()) update(1,1,MX,*it,*(--pre)),clear(1,1,MX,*(nxt),*pre);else update(1,1,MX,*it,0),clear(1,1,MX,*nxt,0);}else if (C[i].y<0){int t=-C[i].y;multiset<int>::iterator it=Set[t].find(C[i].x),pre=it,nxt=it;clear(1,1,MX,*(++nxt),*it);if (pre!=Set[t].begin()) clear(1,1,MX,*it,*(--pre)),update(1,1,MX,*nxt,*pre);else clear(1,1,MX,*it,0),update(1,1,MX,*nxt,0);Set[t].erase(it);}while (nw<=q&&Q[nw].t<C[i+1].t){int t=Q[nw].x,l=0,r=1e8;while (l<r){int mid=(l+r)>>1;if (check(t+mid+1,t-mid)) r=mid;else l=mid+1;}Ans[Q[nw].y]=(!check(t+r+1,t-r)?-1:r);nw++;}}for (int i=1;i<=q;i++) printf("%d\n",Ans[i]);return 0;
}