不跳过任何点的路程=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 ",dis(i,j)); else printf("%d ",asks(1,1,n,i,j-1)+askm(1,1,n,i,j-2)); } } return 0; }