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;

}

  

 

你可能感兴趣的:(USACO)