zoukankan      html  css  js  c++  java
  • [BZOJ5462][APIO2018]新家(线段树+堆)

    其实这个题第一反应一定是线段树分治,但是这样反而更难考虑了(实际上是可做的但很难想到),可见即使看上去最贴切的算法也未必能有效果。

    考虑这个DS题,没有什么模型的转化,可能用到的无非就是线段树、平衡树和堆。

    首先,显然地,将每个商店拆成出现和消失两个事件,然后按时间一次处理。接下来很容易想到二分,于是每次询问的就是[x-mid,x+mid]中是否包含了所有种类的商店。

    考虑如何快速回答询问,我们在+inf处先插入所有种类的商店,并记录每个商店的同种类型的前驱(就是上一个同类型的商店在哪里)。

    注意到,如果某种商店在[x-mid,x+mid]中没有出现,则必然有(x+mid,+inf)中的所有这种商店的前驱必然都小于x-mid。

    问题再次转化为,实时更新每个商店的前驱,以及询问一个后缀最小值。

    第一个操作,我们对每种商店都开一个set即可。第二个操作则是线段树基本操作,可能同坐标上有多个值,这个用可删除堆支持即可。

    这样复杂度是两个log的,但往往线段树和二分可以合并。如果找到最大的i满足[i,+inf)的最小前驱mn,则mn+i<=2*x。

    https://loj.ac/article/523

    线段树上二分,于是复杂度就可以做到一个log了。

     1 #include<set>
     2 #include<queue>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<cstring>
     6 #define lson ls[x],L,mid
     7 #define rson rs[x],mid+1,R
     8 #define Root rt,0,inf
     9 #define rep(i,l,r) for (int i=(l),_=(r); i<=_; i++)
    10 using namespace std;
    11 
    12 const int M=300010,N=M*30,inf=0x3f3f3f3f;
    13 multiset<int>S[M];
    14 int n,k,q,m,x,y,l,t,a,b,cnt,tot,id,rt,ans[M],pos[N],ls[N],rs[N],Mn[N];
    15 struct P{ int op,x,t,k; bool operator <(const P &b)const{ return t!=b.t ? t<b.t : op>b.op; } }w[M*3];
    16 struct H{
    17     priority_queue<int,vector<int>,greater<int> >Q1,Q2;
    18     int size(){ return Q1.size()-Q2.size(); }
    19     void push(int x){ Q1.push(x); }
    20     void erase(int x){ Q2.push(x); }
    21     int top(){ while (Q2.size() && Q1.top()==Q2.top()) Q1.pop(),Q2.pop(); return Q1.top(); }
    22 }Q[M];
    23 
    24 void mdf(int &x,int L,int R,int p,int u,int v){
    25     if (!x) x=++tot;
    26     if (L==R){
    27         if (!pos[x]) pos[x]=++id;
    28         H &q=Q[pos[x]];
    29         if (~u) q.push(u);
    30         if (~v) q.erase(v);
    31         Mn[x]=q.size() ? q.top() : inf;
    32         return;
    33     }
    34     int mid=(L+R)>>1;
    35     if (p<=mid) mdf(lson,p,u,v); else mdf(rson,p,u,v);
    36     Mn[x]=min(Mn[ls[x]],Mn[rs[x]]);
    37 }
    38 
    39 int que(int p){
    40     int L=0,R=inf,x=rt,ans=inf;
    41     while (L!=R){
    42         int mid=(L+R)>>1,tmp=min(ans,Mn[rs[x]]);
    43         if (p<=mid && tmp+mid>=2*p) ans=tmp,R=mid,x=ls[x];
    44         else L=mid+1,x=rs[x];
    45     }
    46     return L-p;
    47 }
    48 
    49 int main(){
    50     freopen("apioa.in","r",stdin);
    51     freopen("apioa.out","w",stdout);
    52     scanf("%d%d%d",&n,&k,&q); Mn[0]=inf;
    53     rep(i,1,k) S[i].insert(-inf),S[i].insert(inf),mdf(Root,inf,-inf,-1);
    54     rep(i,1,n) scanf("%d%d%d%d",&x,&t,&a,&b),w[++m]=(P){1,x,a,t},w[++m]=(P){-1,x,b,t};
    55     rep(i,1,q) scanf("%d%d",&l,&y),w[++m]=(P){0,l,y,i};
    56     sort(w+1,w+m+1);
    57     rep(i,1,m){
    58         P p=w[i];
    59         if (p.op==1){
    60             multiset<int> &s=S[p.k];
    61             multiset<int>::iterator q=s.upper_bound(p.x),r=q--;
    62             mdf(Root,*r,p.x,*q); mdf(Root,p.x,*q,-1);
    63             if (s.size()==2) cnt++; s.insert(p.x);
    64         }
    65         if (p.op==-1){
    66             multiset<int> &s=S[p.k];
    67             s.erase(s.find(p.x));
    68             if (s.size()==2) cnt--;
    69             multiset<int>::iterator q=s.upper_bound(p.x),r=q--;
    70             mdf(Root,*r,*q,p.x); mdf(Root,p.x,-1,*q);
    71         }
    72         if (p.op==0) ans[p.k]=(cnt==k) ? que(p.x) : -1;
    73     }
    74     rep(i,1,q) printf("%d
    ",ans[i]);
    75     return 0;
    76 }
  • 相关阅读:
    angularJS(5)
    angularJS(4)
    angularJS(3)
    AngularJS(1)
    angularJS(2)
    关于响应式布局
    PHP+JQUEY+AJAX实现分页【转】
    bootscript/javascript组件
    你必须收藏的Github技巧
    关于php的一些小知识!
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9151582.html
Copyright © 2011-2022 走看看