【JZOJ5821】【NOIP提高A組模擬2018.8.16】 手機信號(set/權值線段樹)
阿新 • • 發佈:2018-08-17
solution 線段 插入 函數 efi putc 所有 water 打了
Problem
Hint
Solution
- 這道題就是一道考驗你細節處理的題。
- 我們用形如(l,r,v)的三元組表示一個區間的信號站,意為從l到r每隔v有一個信號站。
- 考慮用set/權值線段樹維護這些三元組。
- 我們插入一個三元組的時候,若其與其他三元組的區間互不相交,那自然是最好滴,我們直接丟進set/權值線段樹即可。
- 不然的話,囿於他保證當前區間[l,r]中不存在信號站,即保證當前的區間不包含其他區間,那只有可能被其他區間包含。
- 如圖,記紅色區間為a,灰色區間為b。我們現在要插入a,那麽原本的b中的a這一段肯定是沒有信號站的,數據保證,我們不必管;但它會被分割為l和r兩個子區間。
- l區間的三元組很顯然;r區間的l則並不是a.r+1,而是>a.r中第一個建有信號站的,具體位置可以自己推一推。
- 如果是拆除[l,r]範圍內的信號站,我們可以一個一個地刪掉所有兩個端點均在[l,r]範圍內的三元組。
- 但是,也可能出現上面那種情況,[l,r]在一個三元組內部(或者與一個三元組有交),那麽那個三元組就會被刪去一部分,然後分割成1~2個子區間。
- 如果要查詢點x的話,我們應找到第一個l≥x的三元組,用l-x更新一下d(記d為距離的最小值)。
- 然後,設前面一個三元組為a,用a的最末一個信號站與x的距離更新一下d。
- 此時,這個a可能會包含x,所以判斷一下。如果確實包含,則算出x左右兩邊的兩個信號站的位置,更新一下d。
- 然後便是考驗你們細節處理以及調試時的耐心的時間了。
- 分析一波時間復雜度。設勢能函數為三元組個數,每次插入最多會插入3個、刪除1個三元組,因此每次插入至多使勢能+2;刪除時,每刪去1個三元組勢能-1;查詢的時候,勢能不變。
- 而每次插入、刪除、查詢的復雜度都是\(O(log_2m)\)的。因此:
時間復雜度:\(O(mlog_2m)\)。
Code
我只打了set,畢竟set更短,更舒服,不必打權值線段樹。(畢竟我是c++選手)
#include <bits/stdc++.h> #define A son[v][0] #define B son[v][1] #define fi first #define se second #define mp make_pair #define fo(i,a,b) for(i=a;i<=b;i++) using namespace std; typedef long long ll; typedef pair<int,int> P; const int N=6e6; int i,m,px,py,f; ll c; template<class T> void read(T&x) { char ch=getchar(); x=0; while(!isdigit(ch)) ch=getchar(); while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48), ch=getchar(); } inline void MIN(int&x,int y) {x=min(x,y);} inline void MAX(int&x,int y) {x=max(x,y);} int tot=1,son[N][2]; P tag[N],t[N]; bool des[N]; inline void mark(int v,int l,int r,int f,int s) { int len=r-l; if(s>len) return; tag[v]=mp(f,s); MIN(t[v].fi,l+s); MAX(t[v].se,r-(len-s)%f); } inline void New(int&x) {if(!x) x=++tot;} inline void push(int v,int l,int r,int m) { New(A); New(B); if(des[v]) { des[A]=1, tag[A]=mp(0,0), t[A]=mp(1e9+1,-1); des[B]=1, tag[B]=mp(0,0), t[B]=mp(1e9+1,-1); des[v]=0; return; } int f=tag[v].fi, s=tag[v].se; if(f) { mark(A,l ,m,f,s); mark(B,m+1,r,f,(f-(m+1-s-l)%f)%f); tag[v]=mp(0,0); } } inline void update(int v) { t[v]=mp(1e9+1,-1); if(A) t[v]=t[A]; if(B) t[v]=mp(min(t[v].fi,t[B].fi),max(t[v].se,t[B].se)); } void construct(int v,int l,int r) { int m=l+r>>1; push(v,l,r,m); if(px<=l&r<=py) {mark(v,l,r,f,(f-(l-px)%f)%f); return;} if(px<=m) construct(A,l,m); if(py>m) construct(B,m+1,r); update(v); } void destruct(int v,int l,int r) { if(px<=l&r<=py) {des[v]=1; tag[v]=mp(0,0); t[v]=mp(1e9+1,-1); return;} int m=l+r>>1; push(v,l,r,m); if(px<=m&&A) destruct(A,l,m); if(py>m&&B) destruct(B,m+1,r); update(v); } int query1(int v,int l,int r) { if(t[v].fi>1e9) return -1; if(r<=px) return t[v].se; int m=l+r>>1,x1=-1,x2=-1; push(v,l,r,m); if(A) x1=query1(A,l,m); if(px>m&&B) x2=query1(B,m+1,r); return max(x1,x2); } int query2(int v,int l,int r) { if(t[v].fi>1e9) return 1e9+1; if(px<l) return t[v].fi; int m=l+r>>1,x1=1e9+1,x2=1e9+1; push(v,l,r,m); if(px<m&&A) x1=query2(A,l,m); if(B) x2=query2(B,m+1,r); return min(x1,x2); } int main() { freopen("cellphone.in","r",stdin); freopen("cellphone.out","w",stdout); read(m); read(c); fo(i,1,N-1) t[i]=mp(1e9+1,-1); fo(i,1,m) { switch(getchar()) { case 'c':read(px); read(py); read(f); construct(1,0,1e9); break; case 'd':read(px); read(py); destruct(1,0,1e9); break; case 'q':read(px); if(t[1].fi>1e9) putchar(48); else { int x1=query1(1,0,1e9); int x2=query2(1,0,1e9); ll d=( x1>=0&(x2>1e9|px-x1<x2-px) ? px-x1 : x2-px ); printf("%lld",max(0ll,c-d*d)); } putchar(10); break; } } }
【JZOJ5821】【NOIP提高A組模擬2018.8.16】 手機信號(set/權值線段樹)