1. 程式人生 > >【GDOI2017模擬一試4.11】腐女的生日

【GDOI2017模擬一試4.11】腐女的生日

Description

腐女要過生日了,pty 想給腐女送禮物,但是腐女所在的教室離pty 的教室太遠了,於是pty就拜託會動歸和A星的djy幫忙送禮物。djy在學校建立了一個平面直角座標系,他站在了(0,0)點,腐女在(x0,y0)點,djy每次只能往上下左右四個方向移動一步,中間有n棟矩形教學樓,每個教學樓給出兩個對角的座標,並且保證每棟教學樓的周圍區域(如圖所示)不會有別的教學樓,即djy可以繞一個教學樓走不會碰到任何障礙,現在djy 想知道從起點到終點不碰到任何教學樓,最短需要多少步。

Input

第一行給出X0,y0;
第二行給出n;
下面一行每行x1,y1,x2,y2,表示一對對角的座標;
保證每個矩形都不相交,且一個矩形的周圍區域不會有別的矩形。

Output

輸出只有一行:最短的步數

Sample Input

【樣例輸入1】
9 1
2
5 -3 8 3
10 -3 13 3
【樣例輸入2】
12 0
5
2 -1 3 1
6 -7 8 -1
6 1 8 6
4 3 4 5
10 -5 10 3

Sample Output

【樣例輸出1】
16
【樣例輸出2】
24

Data Constraint

保證所有的y座標在[-10^6,10^6]
所有的x座標在[0,10^6]
70%的資料保證:n<=1000
100%的資料保證:n<=10^5

Solution

這題比較神奇
所有矩形都在Y軸的右邊,考慮一條從左到右,掃描線。
由題意得顯然只能從左往右走,即不會往左走
那麼用一顆線段樹記錄每一個高度的上下走最小走多少步
左右走的在統計答案時加上x0即可
那麼當掃描線到達一個矩形的右邊時,矩形邊上的點只能從矩形兩角走向中間,那麼可以確定要走多遠,或者說找到分界點,進行區間修改,只有單點查詢

Code

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 10010000
#define M 1000001
using namespace std;
int x0,y0,n,last[N],next[N],dat1[N],dat2[N],tot=0,mi=M,ma=-M,b[N],t[N],lz[N];
void putin(int x,int y,int z)
{
    next
[++tot]=last[x];last[x]=tot;dat1[tot]=y;dat2[tot]=z; } void down(int v) { if(lz[v]==0) return; lz[v]=0; b[v*2]=b[v*2+1]=b[v]; t[v*2]=t[v*2+1]=t[v]; lz[v*2]=lz[v*2+1]=1; } int get(int v,int i,int j,int x) { if(i==j) return b[v]+abs((x-M)-t[v]); int m=(i+j)/2;down(v); if(x<=m) return get(v*2,i,m,x); else return get(v*2+1,m+1,j,x); } void change(int v,int i,int j,int x,int y,int d1,int d2) { if(i==x&&j==y) { lz[v]=1;b[v]=d1;t[v]=d2; return; } int m=(i+j)/2;down(v); if(y<=m) change(v*2,i,m,x,y,d1,d2); else if(x>m) change(v*2+1,m+1,j,x,y,d1,d2); else change(v*2,i,m,x,m,d1,d2),change(v*2+1,m+1,j,m+1,y,d1,d2); } int main() { freopen("bl.in","r",stdin); freopen("bl.out","w",stdout); scanf("%d%d%d",&x0,&y0,&n); fo(i,1,n) { int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2); putin(x2+1,y1,y2);mi=min(mi,y1);ma=max(ma,y2); } mi--;ma++; fo(i,0,x0) for(int j=last[i];j;j=next[j]) { int y1=dat1[j],y2=dat2[j],b1=get(1,mi+M,ma+M,y1-1+M),b2=get(1,mi+M,ma+M,y2+1+M),y=b2+y2+y1-b1; if(y1<=y/2) change(1,mi+M,ma+M,y1+M,y/2+M,b1+1,y1); if((y+1)/2<=y2) change(1,mi+M,ma+M,(y+1)/2+M,y2+M,b2+1,y2); } printf("%d\n",x0+get(1,mi+M,ma+M,y0+M)); }