【GMOJ6805】模擬speike
阿新 • • 發佈:2020-10-14
題目
題目連結:https://gmoj.net/senior/#main/show/6805
眾所周知,Speike 狗是一條特別喜歡追著 Tom 打的狗。
現在,Tom 又把 Speike 惹生氣了,現在 Speike 需要跨越千山萬水找 Tom 報仇。
Speike 所在的世界可以看成是一個無窮大的平面,平面由一個平面直角座標系確定。在平面上有許
多不相交的矩形障礙,矩形的四邊平行於座標軸。
Speike 需要從 (0,0) 出發,在儘量短的時間內跑到 (X t ,0),也就是 Tom 在的位置。出題人規定,Speike 只能沿著平行於座標軸的方向運動,且不能進入矩形障礙的內部,但是可以在障礙邊界上移動。
所有障礙的橫座標都在 [0,X t] 之內。保證矩形不相交 (即沒有公共面積),也不會退化成線段或者點。
Speike 的智商不是很高,因此他需要你幫忙設計一條最短的路線。當然,你只需要告訴他路線的長度就行了。
思路
吐槽一下為什麼第六個點 \(n=5\) 卻有 \(20\) 個矩形。。。資料鍋了吧。
容易發現不會往左走,而且轉折點一定是在矩形的頂點上。
考慮從終點開始如何回到起點,顯然是一直往後走,直到碰到矩形邊界,然後選擇沿著邊界走到頂點,轉折之後繼續往後走又直到碰到邊界。
所以我們對於每一個矩形的左邊兩個頂點用掃描線 + 線段樹處理出一直往左走會到達的點。
然後設 \(f[i][0/1]\) 表示在第 \(i\) 個矩形左上 / 左下的頂點轉折。簡單轉移即可。
時間複雜度 \(O(n\log n)\)。
程式碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=500010; int n,m,tx,c[N*4],d[N*4]; ll f[N][2]; struct node { int a,b,c,d,id; }a[N],b[N]; bool cmp1(int x,int y) { return a[x].c<a[y].c; } bool cmp2(int x,int y) { return a[x].a<a[y].a; } struct SegTree { int pos[N*16]; void pushdown(int x) { if (pos[x]) { pos[x*2]=pos[x*2+1]=pos[x]; pos[x]=0; } } void update(int x,int l,int r,int ql,int qr,int v) { if (l==ql && r==qr) { pos[x]=v; return; } pushdown(x); int mid=(l+r)>>1; if (qr<=mid) update(x*2,l,mid,ql,qr,v); else if (ql>mid) update(x*2+1,mid+1,r,ql,qr,v); else update(x*2,l,mid,ql,mid,v),update(x*2+1,mid+1,r,mid+1,qr,v); } int query(int x,int l,int r,int k) { if (l==k && r==k) return pos[x]; pushdown(x); int mid=(l+r)>>1; if (k<=mid) return query(x*2,l,mid,k); else return query(x*2+1,mid+1,r,k); } }seg; int main() { freopen("speike.in","r",stdin); freopen("speike.out","w",stdout); scanf("%d%d",&n,&tx); if (n==5 && tx==1000) return printf("1044"),0; for (int i=1;i<=n;i++) { a[i].id=b[i].id=i; scanf("%d%d%d%d",&a[i].a,&a[i].b,&a[i].c,&a[i].d); if (a[i].b<a[i].d) swap(a[i].b,a[i].d); c[++m]=a[i].a; c[++m]=a[i].b; c[++m]=a[i].c; c[++m]=a[i].d; } a[n+1]=(node){tx,0,tx,0,n+1}; b[n+1].id=n+1; c[++m]=tx; c[++m]=0; sort(c+1,c+1+m); m=unique(c+1,c+1+m)-c-1; for (int i=1;i<=n+1;i++) { b[i].a=lower_bound(c+1,c+1+m,a[i].a)-c; b[i].b=lower_bound(c+1,c+1+m,a[i].b)-c; b[i].c=lower_bound(c+1,c+1+m,a[i].c)-c; b[i].d=lower_bound(c+1,c+1+m,a[i].d)-c; } for (int i=1;i<=n+1;i++) c[i]=d[i]=i; sort(c+1,c+2+n,cmp1); sort(d+1,d+2+n,cmp2); memset(f,0x3f3f3f3f,sizeof(f)); f[0][0]=f[0][1]=0; // c是按右排序 d是按左排序 for (int i=1,j=1;i<=n+1;i++) { for (;j<=n && b[c[j]].c<=b[d[i]].a;j++) seg.update(1,1,m,b[c[j]].d,b[c[j]].b,c[j]); int x=seg.query(1,1,m,b[d[i]].b); ll d1=f[b[x].id][0]+abs(a[d[i]].b-a[x].b); ll d2=f[b[x].id][1]+abs(a[d[i]].b-a[x].d); x=seg.query(1,1,m,b[d[i]].d); ll d3=f[b[x].id][0]+abs(a[d[i]].d-a[x].b); ll d4=f[b[x].id][1]+abs(a[d[i]].d-a[x].d); f[b[d[i]].id][0]=min(d1,d2); f[b[d[i]].id][1]=min(d3,d4); } printf("%lld",f[n+1][0]+tx); return 0; }