2892: 強襲作戰
Time Limit: 50 Sec Memory Limit: 512 MB
Submit: 45 Solved: 30
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
1 2 1
2 3 2
Sample Output
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
3 1
1 2 1
2 3 2
input 2
3 3
1 2 1
2 3 2
Sample Output
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
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 ;
}