zoukankan      html  css  js  c++  java
  • 题解[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
    ",ask(b+1,a-1));
      	else printf("%lld
    ",ask(b+1,a-1+n));
      }
      return 0;
    }
    
    

    完结撒花

  • 相关阅读:
    AJAX请求 $.post方法的使用
    通过jQuery Ajax使用FormData对象上传文件
    iframe跨域访问
    js编码解码
    ajax头像上传
    无边框窗体和用户控件以及权限
    只开启一个窗体和进程以及多线程的操作
    通过一个窗体操作另一个窗体
    流和打印控件用法
    listview和简单的记事本操作
  • 原文地址:https://www.cnblogs.com/xxbbkk/p/14071146.html
Copyright © 2011-2022 走看看