【LOJ】#2585. 「APIO2018」新家
阿新 • • 發佈:2018-12-17
題解
成功把自己寫自閉了
離散化之後再二分我是真不會算座標啊我這個zz
先離散化所有座標,然後對於每個位置維護一個最小前驅,然後線段樹區間維護最小前驅
什麼?位置一樣?那就給每個大小為1的位置開個multiset,往上維護的時候就直接左右區間取min
然後就是,線上段樹上二分了
我們把正無窮和負無窮位置加進去會比較好維護
如果\((x - m,x + m)\)這個區間不合法,轉化為\([x + m,+\infty)\)有前驅在\((-\infty,x - m]\)內
也就意味著我們的距離大小至少是m
線上段樹上二分呢,我們找的是這個\(x + m\)在的區間,顯然x在右區間就往右區間走
如果x在左區間,那麼看看\(mid + 1\)
如果滿足這個\(x + m\)肯定在右區間
不滿足就在左區間
然而,當你二分到一個點的時候,事實上,這個\(x + m\)是可能落在兩個座標中間的,也就是當前節點和當前節點+1,分別計算輸出即可
程式碼
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define pdi pair<db,int> #define mp make_pair #define pb push_back #define enter putchar('\n') #define space putchar(' ') #define eps 1e-8 #define mo 974711 #define MAXN 300005 //#define ivorysi using namespace std; typedef long long int64; typedef double db; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int N,K,Q; struct qry_node { int y,x,t; friend bool operator < (const qry_node &a,const qry_node &b) { if(a.y != b.y) return a.y < b.y; else if(a.t != b.t) return a.t > b.t; return a.x < b.x; } }qry[MAXN * 4]; int qt; int pos[MAXN],tot,ans[MAXN],cnt[MAXN],hs; struct node { int l,r,mq; }tr[MAXN * 4]; multiset<int> S[MAXN]; multiset<int> T[MAXN * 4]; void update(int u) { tr[u].mq = min(tr[u << 1].mq,tr[u << 1 | 1].mq); } void build(int u,int l,int r) { tr[u].l = l;tr[u].r = r; if(l == r) { tr[u].mq = tot + 1; if(l == tot) { tr[u].mq = 1; for(int i = 1 ; i <= K ; ++i) T[u].insert(1); } return; } int mid = (l + r) >> 1; build(u << 1,l,mid); build(u << 1 | 1,mid + 1,r); update(u); } void Change(int u,int pos,int v) { if(tr[u].l == tr[u].r) { if(v > 0) T[u].insert(v); else T[u].erase(T[u].find(-v)); if(T[u].size() >= 1) tr[u].mq = *T[u].begin(); else tr[u].mq = tot + 1; return; } int mid = (tr[u].l + tr[u].r) >> 1; if(pos <= mid) Change(u << 1,pos,v); else Change(u << 1 | 1,pos,v); update(u); } void Query(int u,int x,int suf,int &a) { if(tr[u].l == tr[u].r) { int t = min(tr[u].mq,suf); a = max(a,min(x - pos[t],pos[tr[u].l] - x)); if(tr[u].l < tot) a = max(a,min(x - pos[suf],pos[tr[u].l + 1] - x)); return; } int mid = (tr[u].l + tr[u].r) >> 1; if(x > pos[mid]) {return Query(u << 1 | 1,x,suf,a);} else { int t = min(tr[u << 1 | 1].mq,suf); if(pos[t] > 2 * x - pos[mid + 1]) { return Query(u << 1,x,min(suf,tr[u << 1 | 1].mq),a); } else if(pos[t] <= 2 * x - pos[mid + 1]) {return Query(u << 1 | 1,x,suf,a);} } } void Init() { read(N);read(K);read(Q); int x,t,a,b; for(int i = 1 ; i <= N ; ++i) { read(x);read(t);read(a);read(b); qry[++qt] = (qry_node){a,x,t}; qry[++qt] = (qry_node){b + 1,x,-t}; pos[++tot] = x; } int l,y; for(int i = 1 ; i <= Q ; ++i) { read(l);read(y); qry[++qt] = (qry_node){y,l,- i - K}; //pos[++tot] = l; } pos[++tot] = -1e9;pos[++tot] = 2e9; sort(qry + 1,qry + qt + 1); sort(pos + 1,pos + tot + 1); tot = unique(pos + 1,pos + tot + 1) - pos - 1; build(1,1,tot); } void Solve() { for(int i = 1 ; i <= K ; ++i) { S[i].insert(1),S[i].insert(tot); } for(int i = 1 ; i <= qt ; ++i) { int u = qry[i].t; if(u >= -K) { int x = lower_bound(pos + 1,pos + tot + 1,qry[i].x) - pos; if(u > 0) { S[u].insert(x); auto k = S[u].find(x); auto g = k,h = k;++g,--h; if(*g != *k) { Change(1,*g,*k);Change(1,*g,-(*h)); Change(1,*k,*h); } if(cnt[u] == 0 && cnt[u] + 1 == 1) ++hs; ++cnt[u]; } else { u = -u; auto k = S[u].find(x); auto g = k,h = k;++g,--h; if(*g != *k) { Change(1,*g,-(*k));Change(1,*g,*h); Change(1,*k,-(*h)); } S[u].erase(k); if(cnt[u] == 1 && cnt[u] - 1 == 0) --hs; --cnt[u]; } } else { if(hs != K) ans[- K - u] = -1; else Query(1,qry[i].x,tot + 1,ans[-K - u]); } } for(int i = 1 ; i <= Q ; ++i) { out(ans[i]);enter; } } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Init(); Solve(); }