1. 程式人生 > 實用技巧 >[APIO2018] New Home 新家 題解

[APIO2018] New Home 新家 題解

[APIO2018] New Home 新家 題解

傳送門

首先將時間離散化,然後依據時間建一棵線段樹。將每一個店開業歇業時間搞到樹上。

這樣問題就轉化為:有一個數軸每次加入或刪除一個點。每一個點有一個顏色。在任意時間詢問某一個點距離某一種顏色的最遠距離。到某一個顏色的距離為到這個顏色的點的最小距離。

顯然可以二分答案。每次詢問區間\([l,r]\)是否包含了所有顏色的點。

對於每一個顏色我們搞一個set。記錄每一個點到前面的那個同色的點,也就是前驅,記為pre[i]。

這個玩意的充要條件是在區間\([l,\infty]\) 的pre[i]都滿足>=r。

對於這個我們也可以將座標離散化搞到一個樹上。

時間複雜度是\(O(N\times \log ^2 N)\)

這題也有單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;
}