2892: 強襲作戰

Time Limit: 50 Sec  Memory Limit: 512 MB
Submit: 45  Solved: 30
[Submit][Status][Discuss]

Description

在一個沒有冬馬的世界裡,經歷了學園祭後的春希著急著想要見到心愛的雪菜。然而在排隊想見雪菜的fans太多了,春希一時半會湊不到雪菜面前。
作為高帥富,這樣的問題怎麼能難倒春希?春希從武也手中拿到了取自金閃閃寶庫裡的多啦A夢的傳話筒,並且給每一個排隊的fans都發了一個傳話筒。
於是現在有N個人排成一列,第一個人是雪菜,後面N個人是雪菜的fans。第I個fan能在他的左側中選一個距離不超過L的人發出頻率在[xi,yi]的音波,並且第I個fan也能接受頻率在[xi,yi]的音波。特別的,雪菜能接受所有頻率的音波。
春希有些話想通過傳話筒告訴雪菜,他想選擇一個人作為傳話的起始點,但不知道選誰比較好,作為春希的好友的你,能告訴他答案嗎?
傳話的具體解釋:第I個人能選擇其左邊的距離不超過L的一個人J,只要雙方對應的區間有交集,那麼第I個人就能將資訊傳達給J。然後J又可以繼續找下一個人傳達資訊。傳達一次資訊要1單位時間。

Input

第一行兩個正整數N、L。接下來N-1行,第i行包含了三個正整數xiyili,其中li表示第i個人距離雪菜有li的距離,滿足li嚴格遞增。

Output

總共N-1行,每行一個數分別表示2到N號fan至少需要多少單位時間,雪菜才能收到資訊,如果無法傳到雪菜則輸出-1。

Sample Input

3 1
1 2 1
2 3 2

Sample Output

1
2
【資料規模和約定】
30%的資料滿足N <=20000;
100%的資料滿足2 <=N<= 2.5*10^5、0<=xi,yi,li<=2*10^9,1<=L<=2*10^9,xi<=yi.

HINT

Source

1171: 大sz的遊戲

Time Limit: 50 Sec  Memory Limit: 357 MB
Submit: 320  Solved: 98
[Submit][Status][Discuss]

Description

大sz最近在玩一個由星球大戰改編的遊戲。話說絕地武士當前共控制了N個星球。但是,西斯正在暗處悄悄地準備他們的復仇計劃。絕地評議會也感覺到了這件事。於是,準備加派絕地武士到各星球防止西斯的突襲。一個星球受到攻擊以後,會盡快通知到總基地。需要的時間越長的星球就需要越多絕地武士來防禦。為了合理分配有限的武士,大sz需要你幫他求出每個星球各需要多少時間能夠通知到總基地。由於某種原因,N個星球排成一條直線,編號1至N。其中總基地建在1號星球上。每個星球雖然都是絕地武士控制的,但是上面居住的生物不一定相同,並且科技水平也不一樣。第i個星球能收到並分析波長在[xi, yi]之間的訊號,並且也能夠發出在這個區間的訊號,但是不能發出其他任何波長的訊號。由於技術原因,每個星球只能發訊號到比自己編號小的距離不超過L的星球。特別地,強大的總基地可以接收任何波長的訊號。每個星球處理接收到的資料需要1個單位時間,傳輸時間可以忽略不計。

Input

第一行兩個正整數N、L。接下來N-1行,總共第i行包含了三個正整數xi、yi、li,其中li表示第i個星球距離1號星球li,滿足li嚴格遞增。

Output

總共N-1行,每行一個數分別表示2到N號星球至少需要多少單位時間,總基地能夠處理好資料,如果無法傳到總基地則輸出-1。

Sample Input

input1
3 1
1 2 1
2 3 2
input 2
3 3
1 2 1
2 3 2

Sample Output

output1
1
2
output2
1
1
30%的資料滿足N <=20000;
100%的資料滿足2 <=N<= 2.5*10^5、0<=xi,yi,li<=2*10^9,1<=L<=2*10^9,xi<=yi.

HINT

Source

By 俞華程

Solution

線段樹標記永久化+單調佇列+DP

首先一眼DP:  $dp[i]=min(dp[j])+1$ 其中 $\left | l[i]-l[j] \right |<L,\left [ x[i],y[i] \right ]\bigcap \left [ x[j],y[j] \right ]\neq \O $

那麼需要優化複雜度,考慮利用資料結構(可以利用很多種,這裡選用權值線段樹+單調佇列)

x[],y[]範圍過大,單很稀疏,離散,建權值線段樹,支援區間修改區間查詢;維護區間中的答案,需要在區間中加入一個單調佇列

發現標記不適合下傳,即標記需要永久化,和之前維護直線的思想類似,這樣複雜度就一樣能保證在$O(nlogn)$

如果當前區間完全覆蓋,則不需要下傳;維護的最小值,即區間的單調佇列隊首,和左右區間的最小三者取最小

查詢的時候查詢有交集的所有區間,線段樹中節點的資訊只是維護了完全包含於這個區間的區間的資訊,我們還需要知道和這個區間有交集的但不包含於這個區間的資訊,所以往子樹遞迴的時候把路徑上的資訊也一塊統計就好啦。

總結:

1.標記永久化的思想更加加深

2.對於類似這樣的單調的問題,同樣可以用線段樹去維護,據說類似問題線段樹是比CDQ之類還要無敵的??

3.對於每個線段樹區間套上單調佇列時,容易爆,開始手寫單調佇列,炸編譯,改成動態RE,所以可以考慮用<list>

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<list>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-')f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define maxn 250010
#define inf 0x7fffffff
int N,L,tot,ls[maxn<<],val[maxn<<],dp[maxn],que[maxn],x[maxn],y[maxn],l[maxn];
struct DQueueNode{list<int>q;}Tree[maxn<<];
int Get(int now) {return !Tree[now].q.empty()?dp[Tree[now].q.front()]:inf;}
void update(int now,int l,int r) {val[now]=min(Get(now),(l==r)?inf:min(val[now<<],val[now<<|]));}
void Build(int now,int l,int r)
{
val[now]=inf;
if (l==r) return;
int mid=(l+r)>>;
Build(now<<,l,mid); Build(now<<|,mid+,r);
}
void Insert(int now,int l,int r,int L,int R,int x,int f)
{
if (L<=l && R>=r)
{
if (f) while (!Tree[now].q.empty() && Tree[now].q.front()<=x) Tree[now].q.pop_front();
else {while (!Tree[now].q.empty() && dp[Tree[now].q.back()]>=dp[x]) Tree[now].q.pop_back(); Tree[now].q.push_back(x);}
update(now,l,r);
return;
}
int mid=(l+r)>>;
if (L<=mid) Insert(now<<,l,mid,L,R,x,f);
if (R>mid) Insert(now<<|,mid+,r,L,R,x,f);
update(now,l,r);
}
int Query(int now,int l,int r,int L,int R)
{
if (L<=l && R>=r) return val[now];
int mid=(l+r)>>,re=Get(now);
if (L<=mid) re=min(re,Query(now<<,l,mid,L,R));
if (R>mid) re=min(re,Query(now<<|,mid+,r,L,R));
return re;
}
int main()
{
N=read(),L=read();
for (int i=; i<=N-; i++) ls[++tot]=x[i]=read(),ls[++tot]=y[i]=read(),l[i]=read();
sort(ls+,ls+tot+);
int Tot=; for (int i=; i<=tot; i++) if (ls[i]!=ls[i-]) ls[++Tot]=ls[i];
for (int i=; i<=N-; i++) x[i]=lower_bound(ls+,ls+Tot+,x[i])-ls,y[i]=lower_bound(ls+,ls+Tot+,y[i])-ls;
Tot=unique(ls+,ls+Tot+)-ls-;
// for (int i=1; i<=N-1; i++) printf("%d %d\n",x[i],y[i]);
Build(,,Tot);
int he=-,ta=-; dp[]=; x[]=,y[]=Tot; que[++ta]=;
Insert(,,Tot,x[],y[],,);
for (int i=; i<=N-; i++)
{
int tmp;
while (he<ta && l[i]-l[que[he+]]>L) tmp=que[++he],Insert(,,Tot,x[tmp],y[tmp],tmp,);
dp[i]=Query(,,Tot,x[i],y[i])+;
if (dp[i]!=inf+) printf("%d\n",dp[i]),que[++ta]=i,Insert(,,Tot,x[i],y[i],i,);
else puts("-1");
}
return ;
}