zoukankan      html  css  js  c++  java
  • APIO2018 新家

    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。你的任务是帮助小明求出每对(坐标,时间)二元组居住的不方便指数。
    ((1 leq n,q leq 3*10^5 , 1 leq x_i,a_i,b_i leq 10^9 , 1 leq t_i leq k , a_i leq b_i , 1 leq l_i,y_i leq 10^8))

    题解

    首先很容易想到的是我们可以把一个商店在时间([l,r])营业改为在时间(l)处插入和在时间(r)处删除。这样我们就有了一个大致的算法:将所有的操作按照时间排序,然后顺序地按照时间进行插入,并用某种数据结构动态维护贡献,最后对于每组询问输出答案。
    然后我们考虑如何去维护这个贡献。首先无解的情况是比较好判的,我们就可以直接略过了。然后我们考虑这个答案的计算方法,实际上就是找一段最短的长度(ans),使得([x-ans,x+ans])这段区间中涵盖了所有的商店,这个显然是可以二分答案来解决的。于是问题就转化成为了二分答案之后查询区间不同的数字是否等于(k)。然后继续转化问题,我们记录每一个商店的前驱(即这一种商店上一次出现的位置)如果一种商店在区间([l,r])中出现了,并且这种商店也在([r+1,inf])中出现了,那么这种商店在([r+1,inf])这段区间中,每一个数的前驱必定(geq l),如果在([l,r])中没有出现过,那么在([r+1,inf])区间里面,前驱的最小值一定(leq l)。知道了这个,我们相当于吧问题转化成为了区间询问前驱的最小值。这样实际上我们就已经可以做掉这道题目了,开一个(set)维护每一个商店的前驱(为了方便,在0和inf的两个位置都插入所有种类的商店),然后开一个线段树维护前驱的最小值,每次二分答案之后在线段树上(Check),总共的复杂度为(O(nlog^2(n)))
    然后实际上这题还可以继续优化,我们会发现我们在计算答案的时候,即用到了二分,又用到了线段树。然而实际上,线段树和二分往往是可以并在一起的(雾,然后我们就可以在线段树上直接进行二分。原本二分的时候,我们如果即([i,inf])这段区间的前驱最小值为(Mn),相当于是在找一个最大的位置(i),满足(Mn+i leq 2*x),所以我们直接在线段树上二分即可,方法是这样的:
    假设当前区间为([l,r])

    • 如果(x)([mid+1,r])的范围内,那么说明(i)也一定在([mid+1,r])范围内,直接递归右子树即可。
    • 如果(x)([l,mid])的范围内,那么(i)在左右两个区间都有可能存在,然后判断当前的(mid+1)是否满足(Mn+i leq 2*x)的条件,如果满足则往右子树递归,否则往左子树递归。
      这样做的复杂度就是(O(nlog(n)))的了。

    Code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=3e5+500;
    const int Inf=1e9+7;
    int n,nq,tot,c,sptot,k;
    int srt[N<<2],cnt[N<<1];
    multiset<int>S[N<<1];
    typedef multiset<int>::iterator Sit;
    struct Opt {
      int opt;
      int x,t,tp,idx,ans;
      bool operator < (const Opt &rhs) const {
        return t==rhs.t?opt<rhs.opt:t<rhs.t;
      }
    }p[N<<2];
    bool Cmp(Opt a,Opt b) {
      return a.idx<b.idx;
    }
    
    struct Set {
      priority_queue<int,vector<int>,greater<int> >Q,Del;
      int Top() {
        while(!Del.empty()&&Q.top()==Del.top()) {
          Q.pop();Del.pop();
        }
        return Q.empty()?c+1:Q.top();
      }
    }q[N<<1];
    
    namespace Seg {
      int Mn[N<<4],pos[N<<4];
    #define ls(o) o<<1
    #define rs(o) o<<1|1
      void Build(int o,int l,int r) {
        Mn[o]=Inf;
        if(l==r) {
          pos[o]=srt[l];
          return ;
        }
        int mid=(l+r)>>1;
        Build(ls(o),l,mid);Build(rs(o),mid+1,r);
        pos[o]=pos[ls(o)];
      }
      void Modify(int o,int l,int r,int ps,int v) {
        if(l==r) {
          Mn[o]=srt[v];
          return ;
        }
        int mid=(l+r)>>1;
        if(ps<=mid) Modify(ls(o),l,mid,ps,v);
        else Modify(rs(o),mid+1,r,ps,v);
        Mn[o]=min(Mn[ls(o)],Mn[rs(o)]);
        return ;
      }
      int Query(int o,int l,int r,int ps) {
        if(l==r) return Mn[o];
        int mid=(l+r)>>1;
        if(ps>mid) return Query(rs(o),mid+1,r,ps);
        else return min(Mn[rs(o)],Query(ls(o),l,mid,ps));
      }
      int Ask(int ps) {
        ps=srt[ps];
        int l=0,r=c+1;
        int o=1;
        while(l<r) {
          int mid=(l+r)>>1;
          if(ps>=pos[rs(o)]) o=rs(o),l=mid+1;
          else {
    	    if(pos[rs(o)]+Mn[rs(o)]+1<=2*ps) o=rs(o),l=mid+1;
    	    else o=ls(o),r=mid;
          }
        }
        int Min=Query(1,0,c+1,l+1);
        int ret=max(srt[l],2*ps-Min);
        return ret-ps;
      }
    }
    
    void Init() {
      c=0;
      for(int i=1;i<=tot;i++) {
        srt[++c]=p[i].x;
      }
      sort(srt+1,srt+1+c);
      c=unique(srt+1,srt+1+c)-srt-1;
      srt[0]=-Inf,srt[c+1]=Inf;
      for(int i=1;i<=tot;i++) {
        p[i].x=lower_bound(srt+1,srt+1+c,p[i].x)-srt;
      }
      sort(p+1,p+1+tot);
      for(int i=1;i<=k;i++) {
        S[i].insert(0);
        S[i].insert(c+1);
        q[c+1].Q.push(0);
      }
      Seg::Build(1,0,c+1);
      Seg::Modify(1,0,c+1,c+1,0);
    }
    
    void Insert(int ps,int tp) {
      cnt[tp]++;sptot+=cnt[tp]==1;
      Sit it=S[tp].insert(ps);
      Sit nw=it;it--;
      q[ps].Q.push(*it);
      Seg::Modify(1,0,c+1,ps,q[ps].Top());
      q[*(++nw)].Del.push(*it);
      q[*(nw)].Q.push(ps);
      Seg::Modify(1,0,c+1,*(nw),q[*nw].Top());
      return ;
    }
    
    void Delete(int ps,int tp) {
      cnt[tp]--;sptot-=cnt[tp]==0;
      Sit it=S[tp].find(ps);
      Sit tmp=it,nw=it;it--;
      q[ps].Del.push(*it);
      Seg::Modify(1,0,c+1,ps,q[ps].Top());
      q[*(++nw)].Del.push(*tmp);
      q[*nw].Q.push(*it);
      Seg::Modify(1,0,c+1,*(nw),q[*nw].Top());
      S[tp].erase(tmp);
    }
    
    int main() {
      scanf("%d%d%d",&n,&k,&nq);
      for(int i=1,x,t,a,b;i<=n;i++) {
        scanf("%d%d%d%d",&x,&t,&a,&b);
        p[++tot].opt=-1;p[tot].x=x;p[tot].tp=t;p[tot].t=a;p[tot].idx=Inf;
        p[++tot].opt=1;p[tot].x=x;p[tot].tp=t;p[tot].t=b;p[tot].idx=Inf;
      }
      for(int i=1,l,y;i<=nq;i++) {
        scanf("%d%d",&l,&y);
        p[++tot].opt=0;p[tot].x=l;p[tot].t=y;p[tot].idx=i;
      }
      Init();
      for(int i=1;i<=tot;i++) {
        if(p[i].opt==-1) Insert(p[i].x,p[i].tp);
        else if(p[i].opt==0) {
          if(sptot!=k) p[i].ans=-1;
          else p[i].ans=Seg::Ask(p[i].x);
        }
        else Delete(p[i].x,p[i].tp);
      }
      sort(p+1,p+1+tot,Cmp);
      for(int i=1;i<=nq;i++) {
        printf("%d
    ",p[i].ans);
      }
      return 0;
    }
    
    
  • 相关阅读:
    牌型种数|2015年蓝桥杯B组题解析第七题-fishers
    加法变乘法|2015年蓝桥杯B组题解析第六题-fishers
    九数组分数|2015年蓝桥杯B组题解析第五题-fishers
    [Oracle]Oracle学习小结(1)
    [Oracle]Oracle数据库任何用户密码都能以sysdba角色登入
    【oracle】Enterprise Manager 无法连接到数据库实例。下面列出了组件的状态---个人解决方案
    从两个字符串中找出最大公共子字符串
    Java学习小结(1)-数组的创建与传参
    php学习日志(5)-解决Windows Live Writer错误:WindowsLive.Writer.CoreServices.HttpRequestHelper的类型初始值设定发生异常
    php学习日志(4)-The mbstring extension is missing. Please check your PHP configuration错误及解决方法
  • 原文地址:https://www.cnblogs.com/Apocrypha/p/9909669.html
Copyright © 2011-2022 走看看