牛客網 提高組第8周 T2 推箱子 解題報告
推箱子
鏈接:
https://ac.nowcoder.com/acm/contest/176/B
來源:牛客網
題目描述
在平面上有\(n\)個箱子,每個箱子都可以看成一個矩形,兩條邊都和坐標軸平行。任何兩個矩形都不相交,但可能有某個點或某條邊重合。約定\(x\)軸正方向為右,\(y\)軸正方向為上。
現在\(\tt{Fizzydavid}\)要推這些箱子。他會選擇某個箱子開始,並以每秒\(1\)個單位的速度使這個箱子向右移動。如果路上正面碰上某個箱子,被碰上的箱子會在碰到的那個瞬間開始進入運動狀態,以\(1\)個單位的速度向右移動,不會轉動或改變運動方向。
準確地說,在某個時刻一個箱子\(i\)處於移動狀態當且僅當:\(i\)
\(\tt{Fizzydavid}\)告訴了你所有的信息,需要你求出\(k\)秒後每個矩形的位置。
輸入描述:
第一行兩個整數\(n\),\(t\)和\(k\)。\(\tt{Fizzydavid}\)開始選擇的是輸入的第\(t\)個矩形。
接下來\(n\)行每行四個整數\(x_{1,i},y_{1,i},x_{2,i},y_{2,i}\),表示矩形的左下角坐標是\((x_{1,i},y_{1,i})\)
輸出描述:
輸出一行\(n\)個整數,第\(i\)個整數表示\(k秒\)後第\(i\)個矩形的左下角的\(x\)坐標。你可以發現只要知道這個值就能唯一確定矩形的位置。
說明
對於\(30\%\)的數據,\(k\le 100\)。
對於另外\(40\%\)的數據,\(n\le 1000\)。
對於所有的數據,\(n\le 10^5\),\(1\le t\le n\),\(1\le k\le 10^9\),所有坐標都在\(-10^9\)和\(10^9\)之間。保證任意兩個矩形不相交。
據說正解是優化連邊最短路算法?為什麽不試試類似掃描線的算法呢?(考場上線段樹數組開小爆\(70\)
按照矩形的左邊界\(x\)坐標為關鍵字進行排序,從最開始的那個矩形一個一個做過去。
具體的,對矩形在\(y\)軸方向的凸起用線段樹維護,每次加入一個矩形的時候查詢\(y\)上面區間的最大值,然後看能不能頂到\(\tt{Ta}\)
支持區間賦值和區間最大值就可以了,離散化和動態開點都可以。註意覆蓋情況的小細節。
Code:
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=2e5+10;
struct node
{
int s,t,l,r,id;
bool friend operator <(node n1,node n2){return n1.s<n2.s;}
}mat[N];
int y[N<<1],cnt,n,t,k;
int tag[N<<2],mx[N<<2],ans[N],Time[N];
#define ls id<<1
#define rs id<<1|1
int max(int x,int y){return x>y?x:y;}
void pushdown(int id)
{
if(~tag[id])
{
mx[ls]=mx[rs]=tag[ls]=tag[rs]=tag[id];
tag[id]=-1;
}
}
void change(int id,int L,int R,int l,int r,int d)
{
if(l==L&&r==R)
{
mx[id]=max(mx[id],d);
tag[id]=mx[id];
return;
}
pushdown(id);
int Mid=L+R>>1;
if(r<=Mid) change(ls,L,Mid,l,r,d);
else if(l>Mid) change(rs,Mid+1,R,l,r,d);
else change(ls,L,Mid,l,Mid,d),change(rs,Mid+1,R,Mid+1,r,d);
mx[id]=max(mx[ls],mx[rs]);
}
int query(int id,int L,int R,int l,int r)
{
if(l==L&&r==R) return mx[id];
pushdown(id);
int Mid=L+R>>1;
if(r<=Mid) return query(ls,L,Mid,l,r);
else if(l>Mid) return query(rs,Mid+1,R,l,r);
else return max(query(ls,L,Mid,l,Mid),query(rs,Mid+1,R,Mid+1,r));
}
int main()
{
memset(tag,-1,sizeof(tag));
memset(mx,-1,sizeof(mx));
scanf("%d%d%d",&n,&t,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&mat[i].s,&mat[i].l,&mat[i].t,&mat[i].r);
--mat[i].r;
y[++cnt]=mat[i].r,y[++cnt]=mat[i].l,mat[i].id=i;
}
std::sort(y+1,y+1+cnt);
cnt=std::unique(y+1,y+1+cnt)-y-1;
for(int i=1;i<=n;i++)
{
mat[i].l=std::lower_bound(y+1,y+1+cnt,mat[i].l)-y;
mat[i].r=std::lower_bound(y+1,y+1+cnt,mat[i].r)-y;
}
std::sort(mat+1,mat+1+n);
for(int i=1;i<=n;i++) if(t==mat[i].id) {t=i;break;}
int d=mat[t].s;
change(1,1,cnt,mat[t].l,mat[t].r,mat[t].t-d);
Time[t]=k;
for(int i=t+1;i<=n;i++)
{
int dis=query(1,1,cnt,mat[i].l,mat[i].r);
if(dis==-1) continue;
if(k>=mat[i].s-(dis+d))
{
k-=mat[i].s-(dis+d);
d+=mat[i].s-(dis+d);
change(1,1,cnt,mat[i].l,mat[i].r,mat[i].t-d);
Time[i]=k;
}
else
break;
}
for(int i=1;i<=n;i++)
ans[mat[i].id]=mat[i].s+Time[i];
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}
2018.11.4
牛客網 提高組第8周 T2 推箱子 解題報告