【BZOJ 3387】 线段树= =
57 跨栏训练
为了让奶牛参与运动,约翰建造了 K 个栅栏。每条栅栏可以看做是二维平面上的一条线段,它
们都平行于 X 轴。第 i 条栅栏所覆盖的 X 轴坐标的区间为 [ Ai,Bi ], Y 轴高度就是 i。一开始,奶牛
在坐标 (S,K + 1) 处,它们的家在原点处,所以要想要回家就必须“跨”一些栅栏。
但奶牛们是跨不过栅栏的,它们只能绕过栅栏。在二维平面上,它们只能沿水平和垂直方向移动,
如果前进的道路上出现栅栏,它们就不能前进,必须沿水平方向移动到没有栅栏的地方再前进。奶牛
们希望走的路越短越好,由于在垂直方向上的路程是确定的,你只需要帮它们求出在水平方向的最短
路程就可以了。
输入格式
• 第一行:两个整数 K 和 S, 1 ≤ K ≤ 50000, − 105 ≤ S ≤ 105
• 第二行到第 N + 1 行:第 i + 1 行有两个整数 Ai 和 Bi, − 105 ≤ Ai ≤ Bi ≤ 105
输出格式
• 单个整数:表示奶牛从起点到终点在水平方向移动的最短总距离
样例输入
4 0
-2 1
-1 2
-3 0
-2 1
样例输出
4
解释
第四个栅栏是最先遇到的,向右移一格绕过
它。为了绕过第二个栅栏,再向右移一格,最后
为了回到原点向左移两格
【分析】
就是,差不多,像是个模拟的东西,如果没有东西挡着你,就不用走了(如果要走,等一下有东西挡着你再走)、
如果有东西挡着你,就走到栅栏左边或者栅栏右边(不用多走,要是需要多走,等一下再走)
但是询问区间的话每个点到栅栏左端点需要加的距离是不一样的,所以我们维护的时候不是他走的距离,而是他走的距离在加上他走到图的最左边的距离。
右边也一样。
就是一个区间修改成INF的操作 以及单点修改 还有区间查询。
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define Maxn 200010 9 #define Maxk 50010 10 #define INF 0xfffffff 11 12 int a[Maxk],b[Maxk]; 13 14 struct node 15 { 16 int l,r,lc,rc,a1,a2; 17 bool lazy; 18 }t[Maxn*2];int len; 19 20 int mymin(int x,int y) {return x<y?x:y;} 21 int mymax(int x,int y) {return x>y?x:y;} 22 int mn=INF,mx=0; 23 24 int build(int l,int r) 25 { 26 int x=++len; 27 t[x].l=l;t[x].r=r;t[x].a1=t[x].a2=INF; 28 t[x].lazy=0; 29 if(l!=r) 30 { 31 int mid=(l+r)>>1; 32 t[x].lc=build(l,mid); 33 t[x].rc=build(mid+1,r); 34 } 35 return x; 36 } 37 38 void upd(int x) 39 { 40 if(t[x].lazy==0) return; 41 if(t[x].l!=t[x].r) 42 { 43 int lc=t[x].lc,rc=t[x].rc; 44 t[lc].lazy=1;t[rc].lazy=1; 45 } 46 t[x].a1=t[x].a2=INF; 47 t[x].lazy=0; 48 } 49 50 void change(int x,int l,int r) 51 { 52 if(l>r) return; 53 upd(x); 54 if(t[x].l==l&&t[x].r==r) 55 { 56 t[x].lazy=1; 57 return; 58 } 59 int mid=(t[x].l+t[x].r)>>1; 60 if(r<=mid) change(t[x].lc,l,r); 61 else if(l>mid) change(t[x].rc,l,r); 62 else 63 { 64 change(t[x].lc,l,mid); 65 change(t[x].rc,mid+1,r); 66 } 67 int lc=t[x].lc,rc=t[x].rc; 68 upd(lc);upd(rc); 69 t[x].a1=mymin(t[lc].a1,t[rc].a1); 70 t[x].a2=mymin(t[lc].a2,t[rc].a2); 71 } 72 73 void change2(int x,int y,int z) 74 { 75 upd(x); 76 if(t[x].l==t[x].r) 77 { 78 t[x].a1=mymin(t[x].a1,z+y); 79 t[x].a2=mymin(t[x].a2,z+mx-y); 80 return; 81 } 82 int mid=(t[x].l+t[x].r)>>1; 83 if(y<=mid) change2(t[x].lc,y,z); 84 else change2(t[x].rc,y,z); 85 int lc=t[x].lc,rc=t[x].rc; 86 upd(lc);upd(rc); 87 t[x].a1=mymin(t[lc].a1,t[rc].a1); 88 t[x].a2=mymin(t[lc].a2,t[rc].a2); 89 } 90 91 int query(int x,int l,int r,bool p) 92 { 93 if(l>r) return INF; 94 upd(x); 95 if(t[x].l==l&&t[x].r==r) 96 { 97 if(!p) return t[x].a1; 98 else return t[x].a2; 99 } 100 int mid=(t[x].l+t[x].r)>>1; 101 if(r<=mid) return query(t[x].lc,l,r,p); 102 else if(l>mid) return query(t[x].rc,l,r,p); 103 else return mymin(query(t[x].lc,l,mid,p),query(t[x].rc,mid+1,r,p)); 104 } 105 106 int main() 107 { 108 int k,s; 109 scanf("%d%d",&k,&s); 110 for(int i=1;i<=k;i++) 111 { 112 scanf("%d%d",&a[i],&b[i]); 113 mn=mymin(mn,a[i]); 114 mx=mymax(mx,b[i]); 115 } 116 mn=-mn+1; 117 for(int i=1;i<=k;i++) a[i]+=mn,b[i]+=mn; 118 mx+=mn; 119 len=0; 120 build(1,mx); 121 change2(1,0+mn,0); 122 for(int i=1;i<=k;i++) 123 { 124 int n1=query(1,a[i]+1,b[i]-1,0),n2=query(1,a[i]+1,b[i]-1,1); 125 if(n1!=INF) change2(1,a[i],n1-a[i]); 126 if(n2!=INF) change2(1,b[i],n2-(mx-b[i]) ); 127 change(1,a[i]+1,b[i]-1); 128 129 } 130 s+=mn; 131 int ans=mymin(query(1,1,s,1)-(mx-s),query(1,s,mx,0)-s); 132 printf("%d\n",ans); 133 return 0; 134 }
2016-10-31 15:17:12