• Loj #2585. 「APIO2018」新家


    Loj #2585. 「APIO2018」新家

    题目描述

    五福街是一条笔直的道路,这条道路可以看成一个数轴,街上每个建筑物的坐标都可以用一个整数来表示。小明是一位时光旅行者,他知道在这条街上,在过去现在和未来共有 (n) 个商店出现。第 (i) 个商店可以使用四个整数 (x_i, t_i, a_i, b_i) 描述,它们分别表示:商店的坐标、商店的类型、商店开业的年份、商店关闭的年份。

    小明希望通过时光旅行,选择一个合适的时间,住在五福街上的某个地方。他给出了一份他可能选择的列表,上面包括了 (q) 个询问,每个询问用二元组(坐标,时间)表示。第 (i) 对二元组用两个整数 (l_i, y_i) 描述,分别表示选择的地点 (l_i) 和年份 (y_i)

    现在,他想计算出在这些时间和地点居住的生活质量。他定义居住的不方便指数为:在居住的年份,离居住点最远的商店类型到居住点的距离。类型 (t) 的商店到居住点的距离定义为:在指定的年份,类型 (t) 的所有营业的商店中,到居住点距离最近的一家到居住点的距离。我们说编号为 (i) 的商店在第 (y) 年在营业当且仅当 (a_i leq y leq b_i) 。注意,在某些年份中,可能在五福街上并非所有 (k) 种类型的商店都有至少一家在营业。在这种情况下,不方便指数定义为 −1。你的任务是帮助小明求出每对(坐标,时间)二元组居住的不方便指数。

    输入格式

    第一行包含三个整数 (n)(k)(q),分别表示商店的数量、商店类型的数量和(坐标,时间)二元组的数量。((1leq n,qleq 3 imes 10^5,1leq k leq n))

    接下来 (n) 行,每行包含四个整数 (x_i, t_i, a_i), 和 (b_i) 用于描述一家商店,意义如题面所述((1leq x_i,a_i,b_i leq 10^9,1leq t_i leq k,a_i leq b_i))

    接下来 (q) 行,每行包含两个整数 (l_i), 和 (y_i) ,表示一组(坐标,时间)查询((1leq l_i,y_i leq 10^8))

    输出格式

    对于每组询问输出一个整数,包含(q)个整数,依次表示对于 (q) 组(坐标,时间)询问求出的结果。

    数据范围与提示

    子任务 1(5 分):(n,qleq 400)

    子任务 2(7 分):(n,qleq 6 imes 10^4,kleq 400)

    子任务 3(10 分):(n,qleq 3 imes 10^5),对于所有的商店(a_i=1,b_i=10^8)

    子任务 4(23 分):(n,qleq 3 imes 10^5),对于所有的商店(a_i=1)

    子任务 5(35 分):(n,qleq 6 imes 10^4)

    子任务 6(20 分):(n,qleq 3 imes 10^5)


    先按时间排序,然后一个房子会加入一次,删除一次。

    询问的时候可以二分一个答案。假设位置是(x),二分的答案是(mid),那么如果([l-mid,l+mid])之间(k)种商店都出现了则是一个合法情况。我们对每个商店,记录与它种类相同的前一个商店(pre_i)。如果坐标在([l+mid+1,infty])之间的所有商店满足(pre_igeq l-mid),那么就合法,否则一定不合法。所以我们要维护区间所有商店的(pre)的最小值。

    因为还有删除操作,所有对于线段树上每个点开一个(multiset)

    把坐标离散一下(其实也可以不离散),再对于每个种类加入坐标(-infty)(infty)

    复杂度瓶颈(O(Mlog^2N)),其实可以将二分变成线段树上二分做到一个(log)

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 300005
    
    using namespace std;
    inline int Get() {
    	int x=0,f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9') {
    		if(ch=='-') f=-1;
    		ch=getchar();
    	}
    	while('0'<=ch&&ch<='9') {
    		x=(x<<1)+(x<<3)+ch-'0';
    		ch=getchar();
    	}
    	return x*f;
    }
    
    int n,k,m;
    struct house {
    	int x,t,a,b;
    }s[N];
    
    struct query {
    	int x,t;
    }q[N];
    int T;
    vector<ll>P;
    int Find(ll p) {return upper_bound(P.begin(),P.end(),p)-P.begin()-1;}
    const ll INF=2e9+233;
    void discrete() {
    	static vector<int>d;
    	for(int i=1;i<=n;i++) {
    		d.push_back(s[i].a);
    		d.push_back(s[i].b);
    		P.push_back(s[i].x);
    	}
    	for(int i=1;i<=m;i++) d.push_back(q[i].t);
    	P.push_back(INF),P.push_back(-INF);
    	sort(d.begin(),d.end());
    	d.resize(unique(d.begin(),d.end())-d.begin());
    	sort(P.begin(),P.end());
    	P.resize(unique(P.begin(),P.end())-P.begin());
    	T=d.size();
    	for(int i=1;i<=n;i++) {
    		s[i].a=lower_bound(d.begin(),d.end(),s[i].a)-d.begin()+1;
    		s[i].b=lower_bound(d.begin(),d.end(),s[i].b)-d.begin()+1;
    		s[i].x=lower_bound(P.begin(),P.end(),s[i].x)-P.begin();
    	}
    	for(int i=1;i<=m;i++) {
    		q[i].t=lower_bound(d.begin(),d.end(),q[i].t)-d.begin()+1;
    	}
    }
    
    int rt;
    int ls[N*8],rs[N*8];
    int lx=1,rx=1e9;
    multiset<int>::iterator it;
    multiset<int>st[N*8];
    int mn[N*8];
    int tot;
    #define mp(a,b) make_pair(a,b)
    #define pr pair<int,int>
    vector<pr>add[N<<2],del[N<<2];
    vector<pr>que[N<<2];
    int size[N],appear;
    int ans[N];
    
    int New() {
    	++tot;
    	mn[tot]=P.size()-1;
    	return tot;
    }
    
    void update(int v) {
    	int L=ls[v]?mn[ls[v]]:P.size()-1;
    	int R=rs[v]?mn[rs[v]]:P.size()-1;
    	mn[v]=min(L,R);
    }
    
    void Insert(int &v,int lx,int rx,int p,int val,int flag) {
    	if(!v) v=New();
    	if(lx==rx) {
    		if(flag==1) {
    			st[v].insert(val);
    		} else {
    			st[v].erase(st[v].find(val));
    		}
    		if(st[v].size()) mn[v]=*st[v].begin();
    		else mn[v]=P.size()-1;
    		return ;
    	}
    	int mid=lx+rx>>1;
    	if(p<=mid) Insert(ls[v],lx,mid,p,val,flag);
    	else Insert(rs[v],mid+1,rx,p,val,flag);
    	update(v);
    }
    
    int query(int v,int lx,int rx,int l,int r) {
    	if(!v) return P.size()-1;
    	int ans=mn[v];
    	if(l<=lx&&rx<=r) {
    		return ans;
    	}
    	int mid=lx+rx>>1;
    	if(r<=mid) return query(ls[v],lx,mid,l,r);
    	else if(l>mid) return query(rs[v],mid+1,rx,l,r);
    	else return min(query(ls[v],lx,mid,l,r),query(rs[v],mid+1,rx,l,r));
    }
    
    struct node {
    	multiset<int>pos;
    	void Get_segment(ll l,ll r,int flag) {
    		Insert(rt,lx,rx,r,l,flag);
    	}
    	void Add(int p) {
    		if(pos.find(p)==pos.end()) {
    			it=pos.lower_bound(p);
    			int r=*it;
    			int l=*(--it);
    			Get_segment(l,r,-1);
    			Get_segment(l,p,1);
    			Get_segment(p,r,1);
    		}
    		pos.insert(p);
    	}
    	void Del(int p) {
    		pos.erase(pos.find(p));
    		if(pos.find(p)==pos.end()) {
    			it=pos.lower_bound(p);
    			ll r=*it;
    			ll l=*(--it);
    			Get_segment(l,p,-1);
    			Get_segment(p,r,-1);
    			Get_segment(l,r,1);
    		}
    	}
    	void Init() {
    		pos.insert(0);
    		pos.insert(P.size()-1);
    		Get_segment(0,P.size()-1,1);
    	}
    }coor[N];
    
    int solve(int p) {
    	int l=0,r=1e9,mid;
    	while(l<r) {
    		mid=l+r>>1;
    		int R=lower_bound(P.begin(),P.end(),p+mid+1)-P.begin();
    		if(P[query(rt,lx,rx,R,P.size()-1)]>=p-mid) r=mid;
    		else l=mid+1;
    	}
    	return l;
    }
    
    int main() {
    	n=Get(),k=Get(),m=Get();
    	for(int i=1;i<=n;i++) {
    		s[i].x=Get();
    		s[i].t=Get();
    		s[i].a=Get();
    		s[i].b=Get();
    	}
    	for(int i=1;i<=m;i++) {
    		q[i].x=Get(),q[i].t=Get();
    	}
    	discrete();
    	lx=0,rx=P.size()-1;
    	for(int i=1;i<=n;i++) {
    		add[s[i].a].push_back(mp(s[i].x,s[i].t));
    		del[s[i].b].push_back(mp(s[i].x,s[i].t));
    	}
    	for(int i=1;i<=m;i++) {
    		que[q[i].t].push_back(mp(q[i].x,i));
    	}
    	for(int i=1;i<=k;i++) coor[i].Init();
    	for(int i=1;i<=T;i++) {
    		for(int j=0;j<add[i].size();j++) {
    			size[add[i][j].second]++;
    			if(size[add[i][j].second]==1) appear++;
    			coor[add[i][j].second].Add(add[i][j].first);
    		}
    		if(appear<k) {
    			for(int j=0;j<que[i].size();j++) {
    				ans[que[i][j].second]=-1;
    			}
    	 	} else {
    			for(int j=0;j<que[i].size();j++) {
    				ans[que[i][j].second]=solve(que[i][j].first);
    	 		}
    	 	}
    		for(int j=0;j<del[i].size();j++) {
    			size[del[i][j].second]--;
    			if(size[del[i][j].second]==0) appear--;
    			coor[del[i][j].second].Del(del[i][j].first);
    		}
    	}
    	for(int i=1;i<=m;i++) {
    		cout<<ans[i]<<"
    ";
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Git命令大全
    window系统查看端口被哪个进程占用了
    字体大小自适应纯css解决方案
    CSS3的rem设置字体大小
    javascript同名变量
    西部数码云服务器手记
    十年,站酷已成设计论坛霸主,博客园却成无兵之将
    PHP的性能大坑--strtotime函数
    csv表格处理(上)-- JS 与 PHP 协作导入导出
    致互联网--那些我浅尝则止的昙花
  • 原文地址:https://www.cnblogs.com/hchhch233/p/11025517.html
Copyright © 2020-2023  润新知