1. 程式人生 > >5821. 【NOIP提高A組模擬2018.8.16】 手機訊號

5821. 【NOIP提高A組模擬2018.8.16】 手機訊號

題目描述

這裡寫圖片描述
Input
第一行由一個空格隔開的兩個正整數 m, c,意義見題目描述。
接下來 m 行,每行可能有以下形式:
construct l r v 代表發生了第一種事件;
destruct l r 代表發生了第二種事件;
query x 代表發生了第三種事件。
Output
對於每個 query 操作,請輸出一行一個整數代表此時座標 x 處的訊號強度。

Sample Input
11 10000
query 5
construct 5 500 100
query 500
query 1000
construct 10 90 5
query 44
destruct 44 66
query 55
construct 50 60 3
query 46
query 6000
Sample Output
0
975
0
9999
9775
9984
0

Data Constraint
這裡寫圖片描述

30%

暴力。。。

60%

線段樹隨便搞搞。。。
(話說比賽時居然沒有人寫)

題外話

題解使用set來維護,似乎也可以把詢問掛在線段樹上
然而我並不是這麼做

比賽時就想到了這種方法之後成功寫了一天

0%

考慮直接維護場上的基站情況
顯然一個一個加的話還不如暴力

有一個很顯(sha)然(bi)的方法,每次修改就把區間修改為本次修改的編號
刪除就直接清0
詢問可以在左右各二分出一次最靠近該點的修改,然後用一些奇♂妙的方法求出兩端最近的基站位置

舉個栗子
這裡寫圖片描述
(相同顏色代表同一次修改,豎線代表基站)

二分會找到這裡
這裡寫圖片描述

但是可以發現,左邊找到的不是一個基站,所以再求得該次修改中,在二分位置左邊第一個基站


這裡寫圖片描述

就是這樣,右邊同理

至於怎麼奇♂妙地找到基站,設詢問位置為x,找到的修改編號為Find,a[Find][0/1/2]分別代表詢問的l/r/v(注意兩邊的Find可能不同)
那麼
左邊:min(((l-a[Find][0])/a[Find][2])*a[Find][2]+a[Find][0],a[Find][1])
右邊:max(((l-a[Find][0]+a[Find][2]-1)/a[Find][2])*a[Find][2]+a[Find][0],a[Find][0])

基本思想就是找到當前所在的塊,然後找到塊的其中一段
注意有可能找到的位置超出了範圍,所以要取max/min

其實這樣做有問題
舉個栗子
這裡寫圖片描述


很顯然,最優應該是往左邊走
但是由於該位置被紅色覆蓋了,所以往左往右走都會走到紅色上

所以,需要一些奇♂妙的方法來處理

30%

仔細想想鍋出在哪裡
因為區間不會重疊,所以如果當前段裡只有本次修改那就沒有問題

這裡寫圖片描述
然而,就像上面的例子一樣,如果當前段裡還有其它段的話

這裡寫圖片描述
就會發現當詢問在邊上的兩段時,就無法考慮到藍色段的影響

這裡寫圖片描述
為了解決這個問題,必須要把旁邊的兩段清空(不然會錯)
所以在實際操作中,修改一個區間時,應先把修改的區間所在塊清空再修改(因為區間不會重疊,所以只可能在一個塊中)

刪除操作同理,但是因為刪除的兩個端點可能在不同的塊中,所以要分別考慮(最多兩個塊)
(注意一下刪除和詢問的不同之處,如果刪掉了一個基站那麼要清掉基站連著的塊)

演示一下:
這裡寫圖片描述
修改

這裡寫圖片描述
修改(+清空)

這裡寫圖片描述
修改

這裡寫圖片描述
這裡寫圖片描述
刪除

這裡寫圖片描述
詢問

就是這樣,時間複雜度O(nlog2n)
比100%還難寫所以不調了

100%

然而這樣寫第四個點線段樹就炸了(動態開點)

考慮線上段樹中多維護兩個量,表示當前區間中非0的位置(最左/右)
然後直接詢問,不用二分

沒了。
時間複雜度O(nlogn)
但是常數大到*****
成功墊底
被pascal選手踩在腳下

code

碼量十分清真
這裡寫圖片描述

也就快300行5000byte而已

#include <iostream>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
#define Len 1000000000
#define bj -233333333
using namespace std;

int a[200001][3];
int tr[20000001][6];
int n,m,i,j,k,l,r,mid,len,Find,x,y,z;
char s[15];
long long ans,c;

bool BZ;

void New(int t,int x)
{
    if (!tr[t][x])
    {
        tr[t][x]=++len;
        tr[len][3]=bj;
        tr[len][4]=-1;
        tr[len][5]=Len+1;
    }
}

void cg(int t,int l,int r)
{
    if (tr[t][3]!=bj)
    {
        if (tr[t][3])
        {
            tr[t][4]=r;
            tr[t][5]=l;
        }
        else
        {
            tr[t][4]=-1;
            tr[t][5]=Len+1;
        }
        tr[t][2]=tr[t][3];
    }
}

void down(int t,bool bz,int l,int r)
{
    if (tr[t][3]!=bj)
    {
        if (tr[t][3])
        {
            tr[t][4]=r;
            tr[t][5]=l;
        }
        else
        {
            tr[t][4]=-1;
            tr[t][5]=Len+1;
        }

        tr[t][2]=tr[t][3];

        if (bz)
        {
            tr[tr[t][0]][3]=tr[t][3];
            tr[tr[t][1]][3]=tr[t][3];
        }

        tr[t][3]=bj;
    }
}

void change(int t,int l,int r,int x,int y,int s)
{
    int mid=(l+r)/2;

    if (l<r)
    {
        New(t,0);
        New(t,1);
    }
    down(t,l<r,l,r);

    if (x<=l && r<=y)
    {
        tr[t][3]=s;
        down(t,l<r,l,r);

        return;
    }

    if (x<=mid)
    change(tr[t][0],l,mid,x,y,s);
    if (mid<y)
    change(tr[t][1],mid+1,r,x,y,s);

    if (l<r)
    {
        cg(tr[t][0],l,mid);
        cg(tr[t][1],mid+1,r);
    }

    tr[t][2]=max(tr[tr[t][0]][2],tr[tr[t][1]][2]);

    tr[t][4]=max(tr[tr[t][0]][4],tr[tr[t][1]][4]);
    tr[t][5]=min(tr[tr[t][0]][5],tr[tr[t][1]][5]);
}

void find(int t,int l,int r,int x,int y)
{
    int mid=(l+r)/2;

    if (l<r)
    {
        New(t,0);
        New(t,1);
    }
    down(t,l<r,l,r);

    if (l<r)
    {
        cg(tr[t][0],l,mid);
        cg(tr[t][1],mid+1,r);
    }

    if (x<=l && r<=y)
    {
        Find=max(Find,tr[t][2]);
        return;
    }

    if (x<=mid)
    find(tr[t][0],l,mid,x,y);

    if (Find) return;

    if (mid<y)
    find(tr[t][1],mid+1,r,x,y);
}

void find2(int t,int l,int r,int x,int y,bool type)
{
    int mid=(l+r)/2;

    if (l<r)
    {
        New(t,0);
        New(t,1);
    }
    down(t,l<r,l,r);

    if (l<r)
    {
        cg(tr[t][0],l,mid);
        cg(tr[t][1],mid+1,r);
    }

    if (x<=l && r<=y)
    {
        if (!type)
        Find=max(Find,tr[t][4]);
        else
        Find=min(Find,tr[t][5]);

        return;
    }

    if (x<=mid)
    find2(tr[t][0],l,mid,x,y,type);
    if (mid<y)
    find2(tr[t][1],mid+1,r,x,y,type);
}

int main()
{
    freopen("cellphone.in","r",stdin);
    freopen("cellphone.out","w",stdout);

    tr[0][3]=bj;
    tr[1][3]=bj;
    tr[0][4]=-1;
    tr[0][5]=Len+1;
    len=1;

    scanf("%d%lld",&n,&c);
    fo(i,1,n)
    {
        scanf("%s",s);

        switch (s[0])
        {
            case 'c':
                {
                    scanf("%d%d%d",&x,&y,&z);
                    y=((y-x)/z)*z+x;

                    m++;
                    a[m][0]=x;
                    a[m][1]=y;
                    a[m][2]=z;

                    Find=0;
                    find(1,0,Len,x,y);

                    if (Find)
                    {
                        l=((x-a[Find][0])/a[Find][2])*a[Find][2]+a[Find][0]+1;
                        r=((x-a[Find][0])/a[Find][2]+1)*a[Find][2]+a[Find][0]-1;

                        change(1,0,Len,l,r,0);
                    }
                    change(1,0,Len,x,y,m);

                    break;
                }

            case 'd':
                {
                    scanf("%d%d",&x,&y);

                    if (x)
                    {
                        Find=0;
                        find(1,0,Len,x-1,x-1);
                        if (Find)
                        l=((x-a[Find][0]-1)/a[Find][2])*a[Find][2]+a[Find][0]+1;
                        else
                        l=x;
                    }
                    if (y<Len)
                    {
                        Find=0;
                        find(1,0,Len,y+1,y+1);
                        if (Find && y>=a[Find][0])
                        r=((y-a[Find][0])/a[Find][2]+1)*a[Find][2]+a[Find][0]-1;
                        else
                        r=y;
                    }

                    change(1,0,Len,l,r,0);

                    break;
                }

            case 'q':
                {
                    ans=233333333;
                    ans*=10;

                    scanf("%d",&x);

                    if (!tr[1][2])
                    {
                        printf("0\n");
                        break;
                    }

                    Find=-1;
                    find2(1,0,Len,0,x,0);
                    l=Find;

                    if (l>-1)
                    {
                        Find=0;
                        find(1,0,Len,l,x);

                        if (Find)
                        ans=x-min(((l-a[Find][0])/a[Find][2])*a[Find][2]+a[Find][0],a[Find][1]);
                    }

                    Find=Len+1;
                    find2(1,0,Len,x,Len,1);
                    l=Find;

                    if (l<=Len)
                    {
                        Find=0;
                        find(1,0,Len,x,l);

                        if (Find)
                        ans=min(ans,max(((l-a[Find][0]+a[Find][2]-1)/a[Find][2])*a[Find][2]+a[Find][0],a[Find][0])-x);
                    }

                    printf("%lld\n",max(0,c-ans*ans));
                    break;
                }
        }
    }

    fclose(stdin);
    fclose(stdout);

    return 0;
}