USACO 2014 December Contest Gold T2: Marathon

题目大意

作为一名狂热的马拉松长跑运动员,贝茜喜欢为她的同伴们开设马拉松课程。她最近设计了一个有N个检查点的路线(1 < = N < = 100,000),必须按顺序经过。

不幸的是,贝茜意识到其他的奶牛可能没有足够的耐力跑完全程。因此,她想知道特定的子路线需要多长时间才能跑完,其中的子路线是从完整路线的检查点中截取的的连续子序列。让事情变得更复杂的是,贝西知道其他的牛十分懒惰,可能会选择在任何时候跳过一个检查点——无论哪一种方法都能在最短的时间内完成。然而,他们不允许在子路线中跳过第一个或最后一个检查点。

为了建造最好的马拉松赛道,贝茜想要研究一下在她目前的课程中对检查点位置做出改变后可能造成的后果。请帮助她确定检查点位置的哪些更改将会影响运行不同子路线所需的时间(考虑到奶牛可能会选择在子路线跑步时忽略一个检查点)。

由于该课程设置在市中心的街道网络中,两个检查点之间的距离(x1,y1)和(x2,y2)是由| x1 - x2 | + | y1 - y2 |得出的。

输入格式

第一行给出N和Q(1 <= Q <= 100,000)。

接下来的N行包含N个检查点的(x,y)位置

顺序他们必须沿着路线访问。所有坐标都在-1000 .. 1000范围内。

接下来的Q行包括更新和查询,每行一个,按照给定的顺序进行处理。每行将采用“U I X Y”或“Q I J”形式。形式为“U I X Y”的行表示检查点I(1 <= I <= N)的位置将被改变为位置(X,Y)。“Q I J”形式的一行要求询问点I到检查站J(I <= J)的子路线的最小行程时间,要考虑奶牛选择沿该子路线跳过一个检查点的情况(但不是端点I和J)。

 

题目分析

该题包括询问与更新,很容易想到要用数据结构维护。

 

因为奶牛要按序经过检查点并且询问的是“子序列”,考虑使用线段树维护。

 

线段树的每个叶子结点维护 l 与 l+1 两点间距离sum。

考虑如何维护“跳过检查点的情况”,我们用维护点 l 的叶子结点来维护跳过 l+1 这个点直接到达 l+2点所能缩短的距离del。

这样Pushup时只需把儿子的sum加起来,把儿子的del取个max就行。更新时单点修改即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN=1e5+10;
 4 
 5 int n,q;
 6 int px[MAXN],py[MAXN];
 7 int sum[MAXN<<2],del[MAXN<<2];
 8 char ch[5];
 9 inline int Getd(int a,int b){
10     return fabs(px[a]-px[b])+fabs(py[a]-py[b]);
11 }
12 inline void Build(int k,int l,int r){
13     if(l==r){
14         if(l<n-1) del[k]=Getd(l,l+1)+Getd(l+1,l+2)-Getd(l,l+2);
15         else del[k]=0;
16         if(l<n) sum[k]=Getd(l,l+1);
17         else sum[k]=0;
18         return;
19     }
20     int mid=(l+r)>>1;
21     Build(k<<1,l,mid);
22     Build(k<<1|1,mid+1,r);
23     sum[k]=sum[k<<1]+sum[k<<1|1];
24     del[k]=max(del[k<<1],del[k<<1|1]);
25 }
26 inline int Query_sum(int k,int l,int r,int x,int y){
27     if(l>y||r<x) return 0;
28     if(x<=l&&r<=y) return sum[k];
29     int mid=(l+r)>>1;
30     return Query_sum(k<<1,l,mid,x,y)+Query_sum(k<<1|1,mid+1,r,x,y);
31 }
32 inline int Query_del(int k,int l,int r,int x,int y){
33     if(l>y||r<x) return 0;
34     if(x<=l&&r<=y) return del[k];
35     int mid=(l+r)>>1;
36     return max(Query_del(k<<1,l,mid,x,y),Query_del(k<<1|1,mid+1,r,x,y));
37 } 
38 inline void Update_sum(int k,int l,int r,int x){
39     if(l==r){
40         if(l>=1&&l<n) sum[k]=Getd(l,l+1);
41         else sum[k]=0;
42         return;
43     }
44     int mid=(l+r)>>1;
45     if(x<=mid) Update_sum(k<<1,l,mid,x);
46     else Update_sum(k<<1|1,mid+1,r,x);
47     sum[k]=sum[k<<1]+sum[k<<1|1];
48 }
49 inline void Update_del(int k,int l,int r,int x){
50     if(l==r){
51         if(l>=1&&l<n-1) del[k]=Getd(l,l+1)+Getd(l+1,l+2)-Getd(l,l+2);
52         else del[k]=0;
53         return;
54     }
55     int mid=(l+r)>>1;
56     if(x<=mid) Update_del(k<<1,l,mid,x);
57     else Update_del(k<<1|1,mid+1,r,x);
58     del[k]=max(del[k<<1],del[k<<1|1]);
59 }
60 int main(){
61     scanf("%d%d",&n,&q);
62     for(int i=1;i<=n;++i)
63         scanf("%d%d",&px[i],&py[i]);
64     Build(1,1,n);
65     for(int i=1,p1,p2,p3;i<=q;++i){
66         scanf("%s",ch);
67         if(ch[0]=='Q'){
68             scanf("%d%d",&p1,&p2);
69             --p2;
70             int res=Query_sum(1,1,n,p1,p2);
71             --p2;
72             res-=Query_del(1,1,n,p1,p2);
73             printf("%d\n",res);
74         }
75         else{
76             scanf("%d%d%d",&p1,&p2,&p3);
77             px[p1]=p2;
78             py[p1]=p3;
79             for(int j=p1-1;j<=p1;++j)
80                 Update_sum(1,1,n,j);
81             for(int j=p1-2;j<=p1;++j)
82                 Update_del(1,1,n,j);
83         }
84     }
85     return 0;
86 } 

 

转载于:https://www.cnblogs.com/LI-dox/p/11212635.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值