[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;
}
上一篇:201403-3 命令行选项


下一篇:NX二次开发-NXOPEN获取所有工程图和所有视图DrawingSheet,DrawingSheetCollection,DraftingView