Loj #2585. 「APIO2018」新家

Loj #2585. 「APIO2018」新家

題目描述

五福街是一條筆直的道路,這條道路能夠當作一個數軸,街上每一個建築物的座標均可以用一個整數來表示。小明是一位時光旅行者,他知道在這條街上,在過去如今和將來共有 \(n\) 個商店出現。第 \(i\) 個商店可使用四個整數 \(x_i, t_i, a_i, b_i\) 描述,它們分別表示:商店的座標、商店的類型、商店開業的年份、商店關閉的年份。node

小明但願經過時光旅行,選擇一個合適的時間,住在五福街上的某個地方。他給出了一份他可能選擇的列表,上面包括了 \(q\) 個詢問,每一個詢問用二元組(座標,時間)表示。第 \(i\) 對二元組用兩個整數 \(l_i, y_i\) 描述,分別表示選擇的地點 \(l_i\) 和年份 \(y_i\)c++

如今,他想計算出在這些時間和地點居住的生活質量。他定義居住的不方便指數爲:在居住的年份,離居住點最遠的商店類型到居住點的距離。類型 \(t\) 的商店到居住點的距離定義爲:在指定的年份,類型 \(t\) 的全部營業的商店中,到居住點距離最近的一家到居住點的距離。咱們說編號爲 \(i\) 的商店在第 \(y\) 年在營業當且僅當 \(a_i \leq y \leq b_i\) 。注意,在某些年份中,可能在五福街上並不是全部 \(k\) 種類型的商店都有至少一家在營業。在這種狀況下,不方便指數定義爲 −1。你的任務是幫助小明求出每對(座標,時間)二元組居住的不方便指數。api

輸入格式

第一行包含三個整數 \(n\)\(k\)\(q\),分別表示商店的數量、商店類型的數量和(座標,時間)二元組的數量。\((1\leq n,q\leq 3\times 10^5,1\leq k \leq n)\)app

接下來 \(n\) 行,每行包含四個整數 \(x_i, t_i, a_i\), 和 \(b_i\) 用於描述一家商店,意義如題面所述\((1\leq x_i,a_i,b_i \leq 10^9,1\leq t_i \leq k,a_i \leq b_i)\)spa

接下來 \(q\) 行,每行包含兩個整數 \(l_i\), 和 \(y_i\) ,表示一組(座標,時間)查詢\((1\leq l_i,y_i \leq 10^8)\)code

輸出格式

對於每組詢問輸出一個整數,包含\(q\)個整數,依次表示對於 \(q\) 組(座標,時間)詢問求出的結果。排序

數據範圍與提示

子任務 1(5 分):\(n,q\leq 400\)get

子任務 2(7 分):\(n,q\leq 6\times 10^4,k\leq 400\)it

子任務 3(10 分):\(n,q\leq 3\times 10^5\),對於全部的商店\(a_i=1,b_i=10^8\)io

子任務 4(23 分):\(n,q\leq 3\times 10^5\),對於全部的商店\(a_i=1\)

子任務 5(35 分):\(n,q\leq 6\times 10^4\)

子任務 6(20 分):\(n,q\leq 3\times 10^5\)


先按時間排序,而後一個房子會加入一次,刪除一次。

詢問的時候能夠二分一個答案。假設位置是\(x\),二分的答案是\(mid\),那麼若是\([l-mid,l+mid]\)之間\(k\)種商店都出現了則是一個合法狀況。咱們對每一個商店,記錄與它種類相同的前一個商店\(pre_i\)。若是座標在\([l+mid+1,\infty]\)之間的全部商店知足\(pre_i\geq 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]<<"\n";
    }
    return 0;
}
相關文章
相關標籤/搜索