cogs19461946. 马拉松

【题目描述】


作为一个狂热的马拉松爱好者,Bessie喜欢为她的同行们设计马拉松比赛。她最近刚设计了一款包含N(1 <= N <= 100,000)个检查站的马拉松比赛,比赛要求选手们必须依次通过这N个检查站。

不过,Bessie意识到很多牛们都没有体力跑完全程,她们会选择只跑其中一段。因此,她想知道其中的一段子赛程的长度,子赛程是由全赛程中一些相邻的检查站所组成的。Bessie还知道其它牛们都很懒,她们在跑某段子赛程时会跳过其中一个检查站——那个会导致该段赛程总长最小的检查站。不过不允许她们跳过该段子赛程中的第一个和最后一个点。

为了创建最可行的马拉松比赛,Bessie想调查一下如果改变当前赛程中某个检查站的位置会带来什么影响,请帮她计算改变某个检查站的位置后,跑完某段子赛程所需的最小长度,请注意奶牛们会在这段子赛程中跳过一个检查站。

因为比赛场地设在一个网格区域内,两个检查站之间距离的计算方法是:设两者位置坐标分别为(x1, y1)和(x2, y2),则距离为|x1-x2| + |y1-y2|。


【输入格式】


第一行有两个数N和Q(1 <= Q <= 100,000);

接下来有N行,每行为一个检查站的位置坐标x,y,这N个点给出的顺序即为跑完全程所需依次经过的顺序,所有的坐标值均为-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点不允许跳过)。


【输出格式】

对于每一个子赛程长度查询,输出文件中会对应一行,即所需的最小长度。

【样例输入】

5 5
-4 4
-5 -3
-1 5
-3 4
0 5
Q 1 5
U 4 0 1
U 4 -1 1
Q 2 4
Q 1 4

【样例输出】

11
8
8

【提示】

在此键入。

【来源】

在此键入。

题解 线段树维护区间距离和 以及区间中不走一个点得到的最大收益

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=100000+10;
int x[maxn],y[maxn];
int maxx[maxn*4];
int summ[maxn*4];
int ql,qr;
int n;
inline int abs(int x){
	return x>=0?x:-x;
}
inline void change(int o,int l,int r,int p){
	if(l==r){
		if(l<n)
			summ[o]=abs(x[l+1]-x[l])+abs(y[l+1]-y[l]);
		if(l<n&&l>1)
			maxx[o]=abs(x[l+1]-x[l])+abs(y[l+1]-y[l])+
			abs(x[l-1]-x[l])+abs(y[l-1]-y[l])-
			abs(y[l+1]-y[l-1])-abs(x[l+1]-x[l-1]);
		return ;
	}
	else {
		int mid=(l+r)>>1;
		if(mid>=p)
			change(o<<1,l,mid,p);
		else change(o<<1|1,mid+1,r,p);
		maxx[o]=max(maxx[o<<1],maxx[o<<1|1]);
		summ[o]=summ[o<<1]+summ[o<<1|1];
	}
}
inline int qmax(int o,int l,int r){
	if(l>=ql&&r<=qr)
		return maxx[o];
	else if(l!=r){
		int mid=(l+r)>>1;
		int ans=-0x7fffffff;
		if(mid>=ql)
			ans=max(ans,qmax(o<<1,l,mid));
		if(mid<qr)
			ans=max(ans,qmax(o<<1|1,mid+1,r));
		return ans;
	}
	return -0x7fffffff;
}
inline int qsum(int o,int l,int r){
	if(l>=ql&&r<=qr)
		return summ[o];
	else if(l!=r){
		int mid=(l+r)>>1;
		int ans=0;
		if(mid>=ql)
			ans+=qsum(o<<1,l,mid);
		if(mid<qr)
			ans+=qsum(o<<1|1,mid+1,r);
		return ans;
	}
	return 0;
}
inline void dfs(int o,int l,int r){
	if(l==r){
		if(l<n)
			summ[o]=abs(x[l+1]-x[l])+abs(y[l+1]-y[l]);
		if(l<n&&l>1)
			maxx[o]=abs(x[l+1]-x[l])+abs(y[l+1]-y[l])+
			abs(x[l-1]-x[l])+abs(y[l-1]-y[l])-
			abs(y[l+1]-y[l-1])-abs(x[l+1]-x[l-1]);
		return ;
	}
	else {
		int mid=(l+r)>>1;
		dfs(o<<1,l,mid);
		dfs(o<<1|1,mid+1,r);
		maxx[o]=max(maxx[o<<1],maxx[o<<1|1]);
		summ[o]=summ[o<<1]+summ[o<<1|1];
	}
}
int main(){
	freopen("marathona.in","r",stdin);
	freopen("marathona.out","w",stdout);
	int q;
	scanf("%d %d",&n,&q);
	for(int i=1;i<=n;i++)
		scanf("%d %d",&x[i],&y[i]);
	dfs(1,1,n);
	char C;
	int a,b,c;
	while(q--){
		cin>>C;
		if(C=='U'){
			scanf("%d %d %d",&a,&b,&c);
			x[a]=b;
			y[a]=c;
			change(1,1,n,a);
			if(a>1)
				change(1,1,n,a-1);
			if(a<n)
				change(1,1,n,a+1);
		}
		else {
			scanf("%d %d",&ql,&qr);
			qr--;
			int ans=qsum(1,1,n);
			ql++;
			int an=0;
			if(qr>=ql)
				an=qmax(1,1,n);
			printf("%d\n",ans-an);
		}
	}
return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值