【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]);
    }
}
 
posted @ 2018-11-28 00:18  Newuser233  阅读(12)  评论(0编辑  收藏  举报