[APIO2018] New Home 新家 题解
首先将时间离散化,然后依据时间建一棵线段树。将每一个店开业歇业时间搞到树上。
这样问题就转化为:有一个数轴每次加入或删除一个点。每一个点有一个颜色。在任意时间询问某一个点距离某一种颜色的最远距离。到某一个颜色的距离为到这个颜色的点的最小距离。
显然可以二分答案。每次询问区间 [ l , r ] [l,r] [l,r]是否包含了所有颜色的点。
对于每一个颜色我们搞一个set。记录每一个点到前面的那个同色的点,也就是前驱,记为pre[i]。
这个玩意的充要条件是在区间 [ l , ∞ ] [l,\infin] [l,∞] 的pre[i]都满足>=r。
对于这个我们也可以将坐标离散化搞到一个树上。
时间复杂度是 O ( N × log 2 N ) O(N\times \log ^2 N) O(N×log2N)
这题也有单log的做法,就是在线段树上二分的地方的优化,不想多讲。
code:
(这个代码被卡常了我也懒得改了)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
inline int read()
{
int num = 0, f = 1;
char ch = getchar();
while( !isdigit( ch ) ) { if(ch == '-') f = -1; ch = getchar(); }
while( isdigit( ch ) ) num = (num << 3) + (num << 1) + (ch ^ 48), ch = getchar();
return num * f;
}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=6e5+20;
int n,k,q;
vector<mp> sor;
vector<int> pos_;
int x[MAXN],t[MAXN],a[MAXN],b[MAXN],l[MAXN],y[MAXN];
map<int,int> M;
int find(int f){
//第一个>=f的位置
return lower_bound(ALL(pos_),f)-pos_.begin()+1;
}
const int N=1<<20;
int rest[MAXN];
struct SEGMENTTREE{
int tree[N+N];//最小
SEGMENTTREE(){
memset(tree,63,sizeof(tree));
}
void modify(int index,int val){
index+=N-1;
tree[index]=val;
index>>=1;
while(index){
tree[index]=min(tree[index<<1],tree[index<<1|1]);
index>>=1;
}
}
int query(int a,int b,int now=1,int l=1,int r=N+1){
if(r<=a||l>=b){
return INF;
}
if(r<=b&&l>=a){
return tree[now];
}
int mid=(l+r)>>1;
return min(query(a,b,now<<1,l,mid),query(a,b,now<<1|1,mid,r));
}
}sgt;
set<int> pos[MAXN];
void add(int x_,int t_){
pos[t_].insert(x_);
auto ite=pos[t_].upper_bound(x_);
if(ite!=pos[t_].end()){
sgt.modify(*ite,x_);
}
ite=pos[t_].lower_bound(x_);
if(ite!=pos[t_].begin()){
ite--;
sgt.modify(x_,*ite);
}
else {
sgt.modify(x_,-INF);
}
}
void del(int x_,int t_){
sgt.modify(x_,INF);
pos[t_].erase(x_);
auto ite=pos[t_].upper_bound(x_);
if(ite==pos[t_].end()) return;
if(ite==pos[t_].begin()){
sgt.modify(*ite,-INF);
}
else{
int z=*ite;
ite--;
sgt.modify(z,*ite);
}
}
bool check(int x_,int dis){
int st=find(x_+dis+1);
if(sgt.query(st,N+1)<find(x_-dis)) return 0;
return 1;
}
struct EVENTSEGTREE{
vector<int> tree[N+N];
EVENTSEGTREE(){
}
void add_event(int st,int ed,int val,int now=1,int l=1,int r=N+1){
if(r<=st||l>=ed){
return ;
}
if(r<=ed&&l>=st){
tree[now].PB(val);
return ;
}
int mid=(l+r)>>1;
add_event(st,ed,val,now<<1,l,mid);
add_event(st,ed,val,now<<1|1,mid,r);
}
void run(int now=1,int l_=1,int r_=N+1){
for(auto it:tree[now]){
if(it>0){
add(x[it],t[it]);
}
}
if(l_==r_-1){
for(auto it:tree[now]){
if(it<0){
int lb=0,rb=1e8+1;
if(!check(l[-it],rb)){
rest[-it]=-1;
}
else{
while(lb<rb){
int mid=(lb+rb)>>1;
if(check(l[-it],mid)) rb=mid;
else lb=mid+1;
}
rest[-it]=lb;
}
}
}
}
else{
int mid=(l_+r_)>>1;
run(now<<1,l_,mid);
run(now<<1|1,mid,r_);
}
for(auto it:tree[now]){
if(it>0){
del(x[it],t[it]);
}
}
}
}esgt;
int main(){
// scanf("%d%d%d",&n,&k,&q);
n=read();
k=read();
q=read();
rb(i,1,n){
int xi,ti,ai,bi;
// scanf("%d%d%d%d",&xi,&ti,&ai,&bi);
xi=read();
ti=read();
ai=read();
bi=read();
a[i]=ai;
b[i]=bi;
M[ai]=M[bi]=1;
t[i]=ti;
sor.PB(II(xi,i));
}
rb(i,1,q){
l[i]=read();
y[i]=read();
}
rb(i,1,q){
// scanf("%d%d",&l[i],&y[i]);
M[y[i]]=1;
}
rb(i,1,k){
n++;
a[n]=-INF;
b[n]=INF;
M[a[n]]=M[b[n]]=1;
x[n]=INF;
t[n]=i;
sor.PB(II(x[n],n));
}
sort(ALL(sor));
rep(i,n){
x[sor[i].SEC]=i+1;
pos_.PB(sor[i].FIR);
}
int cnt=0;
for(auto ite=M.begin();ite!=M.end();ite++){
ite->SEC=++cnt;
}
rb(i,1,n){
a[i]=M[a[i]];
b[i]=M[b[i]];
esgt.add_event(a[i],b[i]+1,i);
}
rb(i,1,q){
y[i]=M[y[i]];
esgt.add_event(y[i],y[i]+1,-i);
}
esgt.run();
rb(i,1,q){
printf("%d\n",rest[i]);
}
return 0;
}
UPDATE:
还是补充一下 O ( N × log N ) O(N\times \log N) O(N×logN)的做法吧,(UOJ 已ac!)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
inline int read()
{
int num = 0, f = 1;
char ch = getchar();
while( !isdigit( ch ) ) { if(ch == '-') f = -1; ch = getchar(); }
while( isdigit( ch ) ) num = (num << 3) + (num << 1) + (ch ^ 48), ch = getchar();
return num * f;
}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=6e5+20;
int n,k,q;
vector<mp> sor;
vector<int> pos_;
int x[MAXN],t[MAXN],a[MAXN],b[MAXN],l[MAXN],y[MAXN];
map<int,int> M;
int find(int f){
//第一个>=f的位置
return lower_bound(ALL(pos_),f)-pos_.begin()+1;
}
const int N=1<<20;
int rest[MAXN];
struct SEGMENTTREE{
int tree[N+N];//最小
SEGMENTTREE(){
memset(tree,63,sizeof(tree));
}
void modify(int index,int val){
index+=N-1;
tree[index]=val;
index>>=1;
while(index){
tree[index]=min(tree[index<<1],tree[index<<1|1]);
index>>=1;
}
}
int query(int a,int b,int now=1,int l=1,int r=N+1){
if(r<=a||l>=b){
return INF;
}
if(r<=b&&l>=a){
return tree[now];
}
int mid=(l+r)>>1;
return min(query(a,b,now<<1,l,mid),query(a,b,now<<1|1,mid,r));
}
int low_bound(int pos,int now=1,int l=1,int r=N+1,int MIN=INF){
if(l==r-1) {
int ret=INF;
ret=min(ret,pos_[l-1]-pos);
if(min(tree[now],MIN)>0)
ret=min(ret,pos-pos_[min(tree[now],MIN)-1]);
return ret;
}
int mid=(l+r)>>1;
if(mid>pos_.size()) return low_bound(pos,now<<1,l,mid,min(MIN,tree[now<<1|1]));
if(pos_[mid-1]<=pos) return low_bound(pos,now<<1|1,mid,r,MIN);
if(min(tree[now<<1|1],MIN)!=-INF&&(pos_[mid-2]-pos>=pos-pos_[min(tree[now<<1|1],MIN)-1])){
return low_bound(pos,now<<1,l,mid,min(MIN,tree[now<<1|1]));
}
return low_bound(pos,now<<1|1,mid,r,MIN);
}
}sgt;
set<int> pos[MAXN];
void add(int x_,int t_){
pos[t_].insert(x_);
auto ite=pos[t_].upper_bound(x_);
if(ite!=pos[t_].end()){
sgt.modify(*ite,x_);
}
ite=pos[t_].lower_bound(x_);
if(ite!=pos[t_].begin()){
ite--;
sgt.modify(x_,*ite);
}
else {
sgt.modify(x_,-INF);
}
}
void del(int x_,int t_){
sgt.modify(x_,INF);
pos[t_].erase(x_);
auto ite=pos[t_].upper_bound(x_);
if(ite==pos[t_].end()) return;
if(ite==pos[t_].begin()){
sgt.modify(*ite,-INF);
}
else{
int z=*ite;
ite--;
sgt.modify(z,*ite);
}
}
bool check(int x_,int dis){
int st=find(x_+dis+1);
if(sgt.query(st,N+1)<find(x_-dis)) return 0;
return 1;
}
int main(){
// scanf("%d%d%d",&n,&k,&q);
n=read();
k=read();
q=read();
rb(i,1,n){
int xi,ti,ai,bi;
// scanf("%d%d%d%d",&xi,&ti,&ai,&bi);
xi=read();
ti=read();
ai=read();
bi=read();
a[i]=ai;
b[i]=bi;
M[ai]=M[bi]=1;
t[i]=ti;
sor.PB(II(xi,i));
}
rb(i,1,q){
l[i]=read();
y[i]=read();
}
rb(i,1,q){
// scanf("%d%d",&l[i],&y[i]);
M[y[i]]=1;
}
rb(i,1,k){
n++;
a[n]=-INF;
b[n]=INF;
M[a[n]]=M[b[n]]=1;
x[n]=INF;
t[n]=i;
sor.PB(II(x[n],n));
}
sort(ALL(sor));
rep(i,n){
x[sor[i].SEC]=i+1;
pos_.PB(sor[i].FIR);
}
int cnt=0;
for(auto ite=M.begin();ite!=M.end();ite++){
ite->SEC=++cnt;
}
vector<mp> eve;
rb(i,1,n){
a[i]=M[a[i]];
b[i]=M[b[i]];
eve.PB(II(a[i],i-INF));
eve.PB(II(b[i]+1,i));
}
rb(i,1,q){
y[i]=M[y[i]];
eve.PB(II(y[i],i+INF));
}
sort(ALL(eve));
for(auto &it:eve){
if(it.SEC<0){
add(x[it.SEC+INF],t[it.SEC+INF]);
continue;
}
if(it.SEC<INF){
del(x[it.SEC],t[it.SEC]);
continue;
}
it.SEC-=INF;
int lb=0,rb=1e8+1;
if(!check(l[it.SEC],rb)){
rest[it.SEC]=-1;
}
else{
rest[it.SEC]=sgt.low_bound(l[it.SEC]);
}
}
rb(i,1,q){
printf("%d\n",rest[i]);
}
return 0;
}