【GDOI2017模擬一試4.11】腐女的生日
阿新 • • 發佈:2019-01-23
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));
}