ST表-龙骑士军团【算法赛】

龙骑士军团【算法赛】

问题描述

龙骑士军团是蓝桥王国战斗力最强的军团,该军团总共有 nn 位龙骑士,其中第 ii 位龙骑士的战斗力为 aiai​。

国王想考察一下军团长小蓝对于军团的掌控能力。具体来说,国王会提出 qq 个询问,每次询问给定四个整数 a,b,c,da,b,c,d,并要求小蓝从区间 a,ba,b 中选择一个点 LL,从区间 c,dc,d 中选择一个点 RR,使得 ∑i=LRai∑i=LR​ai​ 的值最大化。

这些问题难倒了小蓝。作为小蓝的助手,请你帮他解决这些问题。针对每个询问,你无需找出具体的 LL 和 RR,只需给出 ∑i=LRai∑i=LR​ai​ 的最大值即可。

输入格式

第一行输入两个整数 n,q(1≤n,q≤2×105)n,q(1≤n,q≤2×105),表示龙骑士数量和国王的询问数量。

第二行输入 nn 个整数 a1,a2,a3,⋯,an(−109≤ai≤109)a1​,a2​,a3​,⋯,an​(−109≤ai​≤109),依稀表示每位龙骑士的战斗力。

接下来 qq 行,每行四个整数 a,b,c,d(1≤a≤b<c≤d≤n)a,b,c,d(1≤a≤b<c≤d≤n),表示一次询问。

输出格式

输出 qq 行,每行一个整数表示答案。

样例输入

复制代码
8 3
-1 2 -3 4 -5 6 -7 8
1 2 3 4
1 1 2 2
1 3 5 8

样例输出

复制代码
3
1
5

样例说明

对于第一个查询,LL 我们可以选择 22,RR 选择 44,区间 2,42,4 的和为 33。

1.暴力版本(超时)

复制代码
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.*;


public class Main {

    static int N=2*100010;
    
    
    static int g[]=new int[N];
     static long s[]=new long[N];
    static int n;
    
    
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
    static BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws IOException { 
        StringTokenizer st=new StringTokenizer(br.readLine());
        n=Integer.parseInt(st.nextToken());
        int q=Integer.parseInt(st.nextToken());
        
        st=new StringTokenizer(br.readLine());
        
        for (int i = 1; i <= n; i++) {
        	g[i]=Integer.parseInt(st.nextToken());
        	s[i]=s[i-1]+g[i];
		}
       
        for (int i = 0; i < q; i++) {
        	st=new StringTokenizer(br.readLine());
        	int a=Integer.parseInt(st.nextToken()),b=Integer.parseInt(st.nextToken());
        	int c=Integer.parseInt(st.nextToken()),d=Integer.parseInt(st.nextToken());
        	long res=0;
        	int l=Math.max(a, b),r=Math.min(c, d);
        	res+=s[r]-s[l-1];
        	long left=0;
        	for (int j = Math.min(a, b); j < l; j++) {
				left=Math.max(left, s[l-1]-s[j-1]);
			}
        	res+=left;
        	long right=0;
        	for (int j = r+1; j <= Math.max(c,d); j++) {
				right=Math.max(right, s[j]-s[r]);
			}
        	res+=right;
        	bw.write(res+"\n");
		}
        
        
        br.close();
        bw.flush();
        bw.close();      
    }
   
}

2优化版本 ST表

复制代码
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.*;


public class Main {

    static int N=2*100010;
    
    
    static int g[]=new int[N];
    static long s[]=new long[N];//long 防止溢出
    static int log2[]=new int[N];
    static int n;
    
    
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
    static BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws IOException { 
        StringTokenizer st=new StringTokenizer(br.readLine());
        n=Integer.parseInt(st.nextToken());
        int q=Integer.parseInt(st.nextToken());
        
        st=new StringTokenizer(br.readLine());
        
        for (int i = 1; i <= n; i++) {
        	g[i]=Integer.parseInt(st.nextToken());
        	s[i]=s[i-1]+g[i];
		}
        log2[1]=0;
        for (int i = 2; i < N; i++) {
			log2[i]=log2[i>>1]+1;
		}
        //题目可以理解为s[j]-s[i]的最大值  i属于[a,b] j属于[c,d]
        //只需要使得s[j]最大 s[i]最小
        
        //构造ST表 倍增表  最大值
        long  f[][]=new long[n+1][log2[n]+1];
        for (int j = 0; j <= log2[n]; j++) {
			for (int i = 0; i+(1<<j)-1 <= n; i++) {//要从0开始 并且要保证右边界合法
				if(j==0)f[i][j]=s[i];
				else f[i][j]=Math.max(f[i][j-1],f[i+(1<<+(j-1))][j-1]);				
			}
		}
       //构造ST表 倍增表  最小值
        long  f1[][]=new long[n+1][log2[n]+1];
        for (int j = 0; j <= log2[n]; j++) {
			for (int i = 0; i+(1<<j)-1 <= n; i++) {
				if(j==0)f1[i][j]=s[i];
				else f1[i][j]=Math.min(f1[i][j-1], f1[i+(1<<+(j-1))][j-1]);				
			}
		}
        
        for (int i = 0; i < q; i++) {
        	st=new StringTokenizer(br.readLine());
        	int a=Integer.parseInt(st.nextToken()),b=Integer.parseInt(st.nextToken());
        	int c=Integer.parseInt(st.nextToken()),d=Integer.parseInt(st.nextToken());
        	//找到a-1到b-1中的最小s值
        	int k=log2[b-a+1];
        	long left=Math.min(f1[a-1][k],f1[b-1-(1<<k)+1][k]);
        	//找到c到d中的最大s值
        	int kk=log2[d-c+1];
        	long right=Math.max(f[c][kk],f[d-(1<<kk)+1][kk]);
        	bw.write((right-left)+"\n" );
		}
        
        
        br.close();
        bw.flush();
        bw.close();      
    }
   
}
相关推荐
Yang_jie_031 小时前
笔记:数据结构(循环队列相关判断条件)
数据结构·笔记
小帽子_1231 小时前
储能 SOC/SOH 精准估算技术:储能工况下算法优化与误差修正方案
算法
hhlongg1 小时前
FFT分析
算法
水龙吟啸2 小时前
华为2026.6.17机考选择题+编程题【速刷敲黑板】
人工智能·深度学习·算法·华为
凌波粒2 小时前
LeetCode--53. 最大子序和(贪心算法)
算法·leetcode·贪心算法
Hesionberger2 小时前
快速求解完全平方数的最少数量
开发语言·数据结构·python·算法·leetcode·c#
c238562 小时前
《序列 DP:C++ 中的“最长”套路与编辑距离》
c++·算法·动态规划
aqiu1111112 小时前
【算法日记 19】LeetCode 1. 两数之和:梦开始的地方,哈希表的降维打击
算法·leetcode·职场和发展
CS创新实验室11 小时前
算法、齿轮与硅基大脑:数值计算发展简史
人工智能·算法·数值计算