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%
仔細想想鍋出在哪裡
因為區間不會重疊,所以如果當前段裡只有本次修改那就沒有問題
然而,就像上面的例子一樣,如果當前段裡還有其它段的話
就會發現當詢問在邊上的兩段時,就無法考慮到藍色段的影響
為了解決這個問題,必須要把旁邊的兩段清空(不然會錯)
所以在實際操作中,修改一個區間時,應先把修改的區間所在塊清空再修改(因為區間不會重疊,所以只可能在一個塊中)
刪除操作同理,但是因為刪除的兩個端點可能在不同的塊中,所以要分別考慮(最多兩個塊)
(注意一下刪除和詢問的不同之處,如果刪掉了一個基站那麼要清掉基站連著的塊)
演示一下:
修改
修改(+清空)
修改
刪除
詢問
就是這樣,時間複雜度
比100%還難寫所以不調了
100%
然而這樣寫第四個點線段樹就炸了(動態開點)
考慮線上段樹中多維護兩個量,表示當前區間中非0的位置(最左/右)
然後直接詢問,不用二分
沒了。
時間複雜度
但是常數大到*****
成功墊底
被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;
}