BZOJ3825 : [Usaco2014 Nov]Marathon

不跳过任何点的路程=dis(l,l+1)+dis(l+1,l+2)+...+dis(r-2,r-1)+dis(r-1,r)

要跳过一个点i,则要最小化dis(i,i+2)-dis(i,i+1)-dis(i+1,i+2)

于是用线段树支持单点修改、区间查询和以及最小值即可

 

#include<cstdio>
#define N 100010
int n,m,i,j,loc[N][2],vs[N<<2],vm[N<<2];char op[5];
inline int abs(int x){return x>0?x:-x;}
inline int dis(int a,int b){return abs(loc[a][0]-loc[b][0])+abs(loc[a][1]-loc[b][1]);}
inline void min(int&a,int b){if(a>b)a=b;}
inline void cal(int x,int p){vs[x]=dis(p,p+1),vm[x]=dis(p,p+2)-dis(p,p+1)-dis(p+1,p+2);}
inline void up(int x){vs[x]=vs[x<<1]+vs[x<<1|1],vm[x]=vm[x<<1]<vm[x<<1|1]?vm[x<<1]:vm[x<<1|1];}
void build(int x,int a,int b){
  if(a==b){cal(x,a);return;}
  int mid=(a+b)>>1;
  build(x<<1,a,mid),build(x<<1|1,mid+1,b),up(x);
}
void change(int x,int a,int b,int c){
  if(a==b){cal(x,a);return;}
  int mid=(a+b)>>1;
  if(c<=mid)change(x<<1,a,mid,c);else change(x<<1|1,mid+1,b,c);
  up(x);
}
int asks(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d)return vs[x];
  int mid=(a+b)>>1,t=0;
  if(c<=mid)t=asks(x<<1,a,mid,c,d);
  if(d>mid)t+=asks(x<<1|1,mid+1,b,c,d);
  return t;
}
int askm(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d)return vm[x];
  int mid=(a+b)>>1,t=~0U>>1;
  if(c<=mid)t=askm(x<<1,a,mid,c,d);
  if(d>mid)min(t,askm(x<<1|1,mid+1,b,c,d));
  return t;
}
int main(){
  scanf("%d%d",&n,&m);
  for(i=1;i<=n;i++)scanf("%d%d",&loc[i][0],&loc[i][1]);
  build(1,1,n);
  while(m--){
    scanf("%s%d",op,&i);
    if(op[0]=='U'){
      scanf("%d%d",&loc[i][0],&loc[i][1]);
      change(1,1,n,i);
      if(i>1)change(1,1,n,i-1);
      if(i>2)change(1,1,n,i-2);
    }else{
      scanf("%d",&j);
      if(i==j)puts("0");
      else if(i+1==j)printf("%d\n",dis(i,j));
      else printf("%d\n",asks(1,1,n,i,j-1)+askm(1,1,n,i,j-2));
    }
  }
  return 0;
}

  

 

posted @ 2014-12-31 20:59  Claris  阅读(286)  评论(0编辑  收藏  举报