题解[CF515E Drazil and Park]

题目描述

Luogu

CF

\(n\)个点,每个点有权值\(h[i]\),第\(i\)个点与第\(j\)个点距离为\(d[i]\),第\(1\)个点与第\(n\)个点相邻,\(Q\)次询问,每次询问给出\(1\)段区间,求区间内的两个点\(i,j\),使\(dis(i,j)+2*(h_i+h_j)\)最大。

题目分析

一 环状:考虑断环为链;

二 最大化 \(dis(i,j)+2(h_i+h_j)\)

前缀和维护\(dis(i,j)=sum_j-sum_i\)

式子拆掉

= \(sum_j-sum_i+2*h_i+2*h_j\)

\(i\)相关的放一起, 与\(j\)相关的放一起

=\(sum_j+2*h_j-(sum_i-2*h_i)\)

所以要最大化\(sum_j+2*h_j\),最小化\(sum_i-2*h_j\)

可以用\(ST\)表、线段树维护区间最值

三 注意到\(i,j\)应为不同的两点,而直接用\(ST\)表存最值可能会出现两处最值在同一个点上,所以在处理\(ST\)表的同时要存一下最值的下标。如果在查询时遇到\((l,r)\)最大最小在同一个点\(pos\)上的情况,处理出\((l,pos-1)\)\((pos+1,r)\)的最大最小值所在的位置,再与\(pos\)组合即可。

四 记得开\(long\) \(long\)

code

#include<bits/stdc++.h>
#define ll long long
#define N (500010)
using namespace std;
ll n,Q,a,b,t=22;
ll d[N],s[N],h[N];
//d:距离 h:如题 s:距离的前缀和
ll st1[N][25],st2[N][25],p1[N][25],p2[N][25];
//st1:最大值  st2:最小值
//p1:最大值的位置 p2:最小值的位置
inline void pre(){
  for(int i=1;i<=n+n;i++){
  	st1[i][0]=s[i]+2*h[i];
  	st2[i][0]=s[i]-2*h[i];
  	p1[i][0]=p2[i][0]=i;
  }
  for(int j=1;j<t;j++){
  	for(int i=1;i<=n+n;i++){
  		if((i+(1<<(j-1)))>n+n) break;
  		st1[i][j]=max(st1[i][j-1],st1[i+(1<<(j-1))][j-1]);
  		if(st1[i][j-1]>st1[i+(1<<(j-1))][j-1]) p1[i][j]=p1[i][j-1];
  		else p1[i][j]=p1[i+(1<<(j-1))][j-1];
  		st2[i][j]=min(st2[i][j-1],st2[i+(1<<(j-1))][j-1]);
  		if(st2[i][j-1]<st2[i+(1<<(j-1))][j-1]) p2[i][j]=p2[i][j-1];
  		else p2[i][j]=p2[i+(1<<(j-1))][j-1];
  	}
  }
  return;
}
//ST表预处理
inline ll askmax(ll l,ll r){
  ll tt=log2(r-l+1);
  if(st1[l][tt]>st1[r-(1<<tt)+1][tt]) return p1[l][tt];
  return p1[r-(1<<tt)+1][tt];
}
inline ll askmin(ll l,ll r){
  ll tt=log2(r-l+1);
  if(st2[l][tt]<st2[r-(1<<tt)+1][tt]) return p2[l][tt];
  return p2[r-(1<<tt)+1][tt];
}
//查询最大最小值所在的位置
inline ll calc(ll x,ll y){return s[x]+2*h[x]-s[y]+2*h[y];}
//计算两点之间的贡献
inline ll ask(ll l,ll r){
  ll pos1=askmax(l,r),pos2=askmin(l,r);
  if(pos1!=pos2) return calc(pos1,pos2);
  else{
  	if(pos1>l&&pos1<r){
  	   ll res1=max(calc(pos1,askmin(l,pos1-1)),calc(pos1,askmin(pos1+1,r)));
  	   ll res2=max(calc(askmax(l,pos1-1),pos1),calc(askmax(pos1+1,r),pos1));
  	   return max(res1,res2);
  	}
  	if(pos1==l&&pos1<r){
  		ll res1=max(calc(askmax(pos1+1,r),pos1),calc(pos1,askmin(pos1+1,r)));
  		return res1;
  	}
  	if(pos1==r&&pos1>l){
  		ll res1=max(calc(askmax(l,pos1-1),pos1),calc(pos1,askmin(l,pos1-1)));
  		return res1;
  	}
  }
  return 0;
}
//如题解
int main(){
  scanf("%lld%lld",&n,&Q);
  for(int i=1;i<=n;i++){
  	scanf("%lld",&d[i]);
  	d[n+i]=d[i];
  	s[i+1]=s[i]+d[i];
  }
  for(int i=n+1;i<=n+n;i++) s[i+1]=s[i]+d[i];
  for(int i=1;i<=n;i++){
  	scanf("%lld",&h[i]);
  	h[i+n]=h[i];
  }
  pre();
  while(Q--){
  	scanf("%lld%lld",&a,&b);
  	if(a>b) printf("%lld\n",ask(b+1,a-1));
  	else printf("%lld\n",ask(b+1,a-1+n));
  }
  return 0;
}

完结撒花

posted @ 2020-12-01 22:05  xxbbkk  阅读(237)  评论(0编辑  收藏  举报