1. 程式人生 > >【JZOJ5821】【NOIP提高A組模擬2018.8.16】 手機信號(set/權值線段樹)

【JZOJ5821】【NOIP提高A組模擬2018.8.16】 手機信號(set/權值線段樹)

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/權值線段樹)