【APIO2018新家】神奇的变换+set和线段树和删除堆维护前驱
我居然参加过APIO2018?怎么我感觉做这道题的时候完全没有印象?orz orz orz
BZOJ5462
5462: [APIO2018] 新家
Time Limit: 50 Sec Memory Limit: 256 MB Submit: 8 Solved: 5 [Submit][Status][Discuss]Description
五福街是一条笔直的道路,这条道路可以看成一个数轴,街上每个建筑物的坐标都可以用一个整数来表示。小明是
一位时光旅行者,他知道在这条街上,在过去现在和未来共有 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 <= y <= b_i
。注意,在某些年份中,可能在五福街上并非所有 k 种类型的商店都有至少一家在营业。在这种情况下,不方便
指数定义为 -1。你的任务是帮助小明求出每对(坐标,时间)二元组居住的不方便指数。
Input
第一行包含三个整数 n , k 和 q,分别表示商店的数量、商店类型的数量和(坐标,时间)二元组的数量。
接下来 n 行,每行包含四个整数 x_i, t_i, a_i, 和 b_i 用于描述一家商店,意义如题面所述
接下来 q 行,每行包含两个整数 l_i, 和 y_i ,表示一组(坐标,时间)查询
(1<= n,q<= 3e5,1<= k <= n)
(1<= x_i,a_i,b_i <= 1e9,1<= t_i <= k,a_i <= b_i)
(1<= l_i,y_i <= 1e8)
Output
输出一行,包含q个整数,依次表示对于q组(坐标、时间)询问求出的结果。
Sample Input
4 2 4
3 1 1 10
9 2 2 4
7 2 5 7
4 1 8 10
5 3
5 6
5 9
1 10
Sample Output
4
2
-1
-1
HINT
Source
对于该题的时间操作,我们可以搞一个一维的扫描线,把商店[L,R]时间存在转化为时间L加入一个商店,R+1删去一个商店。如果我们考虑二分最终的答案ans,那么对于某个时间点上,坐标在x上的询问,我们需要做的就是查询[x-ans,x+ans]是否包含了所有类型的商店。 如果某个商店x他对应的同类型商店的上一个位置定义为他的前驱pre,那么显然对于我们查询的这段区间不能被[pre+1,x-1]所包含。我们再加推广,我们要二分判断的这段区间不能被所有的点的[pre+1,x-1]所包含,而可能产生包含的就是[x+ans+1,inf)这段区间的pre。如果在这段区间的pre中的最小值跨过了x-ans,也即min pre < x-ans,那么就一定有个点跳过了我们判断的这段区间,那么就说明这段区间不能包含所有k种商店,否则就可以。以此我们利用set来维护每个点的pre,利用线段树来维护后继最小值,对于某个位置上可能有多个商店,在每个结点上开一个可删除堆来取得单点上的min pre。 这样做发现修改是nlogn,查询是nlog^2n的。但实际上我们发现我们可以做到在线段树上二分(因为他之前可以二分显然是可以满足单调性的)。具体原理见某神奇的loj讨论区 又丑又烂还是log^2n的code#include<stdio.h> #include<cstdio> #include<algorithm> #include<set> #include<iostream> #include<queue> #include<vector> using namespace std; const int maxn = 300005; const int inf = 0x3f3f3f3f; struct qe{ priority_queue<int,vector<int>,greater<int> >q1,q2; int top() { while( (q1.size()&&q2.size() )&&(q1.top()==q2.top()) ) q1.pop(),q2.pop(); return q1.size()?q1.top():inf; }; void ins(int x) { q1.push(x); } void del(int x) { q2.push(x); } }qo[maxn*4]; int qtot; int N,K,Q;; multiset<int>se[maxn]; struct node{ node *ls,*rs; int mi; qe *q; }z[maxn*30],*rt,*tl; void upd(node *&p) { p->mi = inf; if(p->ls!=NULL) p->mi = min(p->mi,p->ls->mi); if(p->rs!=NULL) p->mi = min(p->mi,p->rs->mi); } void change(node *&p,int l,int r,int ps,int las,int now) { if(p==NULL) p = ++tl; if(l==r) { if(p->q==NULL) p->q = &qo[++qtot]; if(las!=-233) p->q->del(las); if(now!=-233) p->q->ins(now); p->mi = p->q->top(); return; } int mid = (l+r)>>1; if(ps<=mid) change(p->ls,l,mid,ps,las,now); else change(p->rs,mid+1,r,ps,las,now); upd(p); } int getmin(node *&p,int l,int r,int x,int y) { if(x>y) return -inf; if(p==NULL) return inf; if(x<=l&&r<=y) return p->mi; int mid = (l+r)>>1; if(y<=mid) return getmin(p->ls,l,mid,x,y); else if(x>mid) return getmin(p->rs,mid+1,r,x,y); else return min(getmin(p->ls,l,mid,x,y),getmin(p->rs,mid+1,r,x,y)); } int ANS[maxn]; struct dd{ int tim,xs,id,x; }oo[maxn*4]; int orz; bool cmp(dd aa,dd bb) { return aa.tim!=bb.tim?aa.tim<bb.tim:aa.xs<bb.xs; } bool isok(int x,int cd) { if(getmin(rt,0,inf,min(x+cd+1,inf),inf)<x-cd) return 0; return 1; } int main() { tl = z; scanf("%d%d%d",&N,&K,&Q); for(int i=1;i<=K;i++) { se[i].insert(-inf); se[i].insert(inf); change(rt,0,inf,inf,-233,-inf); } for(int i=1;i<=N;i++) { int x,t,a,b; scanf("%d%d%d%d",&x,&t,&a,&b); oo[++orz] = (dd){b+1,-1,t,x};//del oo[++orz] = (dd){a,-233,t,x};//add time sxing leixing weizhi } for(int i=1;i<=Q;i++) { int L,Y; scanf("%d%d",&L,&Y); oo[++orz] = (dd){Y,i,0,L};//zuobiao iid weizhi } sort(oo+1,oo+1+orz,cmp); for(int i=1;i<=orz;i++) { if(oo[i].xs==-1) { multiset<int>::iterator hj = se[oo[i].id].lower_bound(oo[i].x); hj++; multiset<int>::iterator qq = se[oo[i].id].lower_bound(oo[i].x); qq--; change(rt,0,inf,*hj,oo[i].x,*qq); change(rt,0,inf,oo[i].x,*qq,-233); se[oo[i].id].erase(se[oo[i].id].find(oo[i].x)); } else if(oo[i].xs==-233) { multiset<int>::iterator hj = se[oo[i].id].upper_bound(oo[i].x); multiset<int>::iterator qq = hj; qq--; change(rt,0,inf,*hj,*qq,oo[i].x); change(rt,0,inf,oo[i].x,-233,*qq); se[oo[i].id].insert(oo[i].x); } else { int L = 0,R = inf-oo[i].x,mid,ans=-1; while(L<=R) { mid = (L+R)/2; if(isok(oo[i].x,mid)) ans = mid,R=mid-1; else L=mid+1; } ANS[oo[i].xs] = ans; } } for(int i=1;i<=Q;i++) { printf("%d\n",ANS[i]); } }