Java GSS1-SPOJ-段树TLE
我用一个段树来解决这个问题。我在每个节点上保存总和max、最左边的max和最右边的max。然后我搜索图表以找到特定时间间隔的答案。如何提高此代码的速度Java GSS1-SPOJ-段树TLE,java,algorithm,optimization,segment-tree,Java,Algorithm,Optimization,Segment Tree,我用一个段树来解决这个问题。我在每个节点上保存总和max、最左边的max和最右边的max。然后我搜索图表以找到特定时间间隔的答案。如何提高此代码的速度 import java.util.Scanner; //TLE class GSS1 { static class Node{ int max; int MaxL; int MaxR; int sum; public Node(int max, int MaxL, int MaxR, int sum)
import java.util.Scanner;
//TLE
class GSS1 {
static class Node{
int max;
int MaxL;
int MaxR;
int sum;
public Node(int max, int MaxL, int MaxR, int sum){
this.max=max;
this.MaxL=MaxL;
this.MaxR=MaxR;
this.sum=sum;
}
public Node(){
}
}
static class SegmentTree{
private Node[] tree;
private int maxsize;
private int height;
private final int STARTINDEX = 0;
private final int ENDINDEX;
private final int ROOT = 0;
Node s;
public SegmentTree(int size){
height = (int)(Math.ceil(Math.log(size) / Math.log(2)));
maxsize = 2 * (int) Math.pow(2, height) - 1;
tree = new Node[maxsize];
for(int i=0;i<tree.length;i++){
tree[i]=new Node();
}
ENDINDEX = size - 1;
s=new Node();
s.MaxL=Integer.MIN_VALUE;
s.MaxR=Integer.MIN_VALUE;
s.sum=Integer.MIN_VALUE;
s.max=Integer.MIN_VALUE;
}
private int leftchild(int pos){
return 2 * pos + 1;
}
private int rightchild(int pos){
return 2 * pos + 2;
}
private int mid(int start, int end){
return (start + (end - start) / 2);
}
private Node constructSegmentTreeUtil(int[] elements, int startIndex, int endIndex, int current){
if (startIndex == endIndex)
{
tree[current].max=tree[current].MaxL=tree[current].MaxR=tree[current].sum=elements[startIndex];
return tree[current];
}
int mid = mid(startIndex, endIndex);
Node left=constructSegmentTreeUtil(elements, startIndex, mid, leftchild(current));
Node right=constructSegmentTreeUtil(elements, mid + 1, endIndex, rightchild(current));
tree[current].max = Math.max(left.max, right.max);
tree[current].MaxL = Math.max(left.MaxL , left.sum+right.MaxL);
tree[current].MaxR = Math.max(right.MaxR , right.sum+left.MaxR);
tree[current].sum = left.sum+right.sum;
return tree[current];
}
public void constructSegmentTree(int[] elements){
constructSegmentTreeUtil(elements, STARTINDEX, ENDINDEX, ROOT);
}
private Node getSumUtil(int startIndex, int endIndex, int queryStart, int queryEnd, int current){
if (queryStart <= startIndex && queryEnd >= endIndex ){
return tree[current];
}
if (endIndex < queryStart || startIndex > queryEnd){
return s;
}
int mid = mid(startIndex, endIndex);
Node left=getSumUtil(startIndex, mid, queryStart, queryEnd, leftchild(current));
Node right=getSumUtil( mid + 1, endIndex, queryStart, queryEnd, rightchild(current));
Node current_Node=new Node();
current_Node.max = Math.max(left.max, right.max);
current_Node.MaxL = Math.max(left.MaxL , left.sum+right.MaxL);
current_Node.MaxR = Math.max(right.MaxR , right.sum+left.MaxR);
current_Node.sum = left.sum+right.sum;
return current_Node;
}
public int getMaxSum(int queryStart, int queryEnd){
if(queryStart < 0 || queryEnd > tree.length)
{System.out.println("inside negative");
return Integer.MIN_VALUE;
}
return getMax(getSumUtil(STARTINDEX, ENDINDEX, queryStart, queryEnd, ROOT));
}
public int getMax(Node r){
return Math.max(Math.max(r.max, r.MaxL),Math.max(r.MaxR, r.sum));
}
public int getFirst(){
return tree[0].MaxL;
}
}
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int numbers[]=new int [input.nextInt()];
for(int i=0;i<numbers.length;i++){
numbers[i]=input.nextInt();
}
SegmentTree tree=new SegmentTree(numbers.length);
tree.constructSegmentTree(numbers);
int cases=input.nextInt();
int x;
int y;
int query;
for(int i=0;i<cases;i++){
x=input.nextInt()-1;
y=input.nextInt()-1;
System.out.println(tree.getMaxSum(x, y));
}
}
}
import java.util.Scanner;
//TLE
GSS1类{
静态类节点{
int max;
int-MaxL;
int-MaxR;
整数和;
公共节点(int max、int MaxL、int MaxR、int sum){
这个。max=max;
这个.MaxL=MaxL;
这个.MaxR=MaxR;
这个。sum=sum;
}
公共节点(){
}
}
静态类分段树{
私有节点[]树;
私有int-maxsize;
私人内部高度;
私有最终int STARTINDEX=0;
私人最终内部索引;
私有最终整数根=0;
节点s;
公共分段树(整数大小){
高度=(int)(Math.ceil(Math.log(size)/Math.log(2));
maxsize=2*(整数)数学功率(2,高度)-1;
树=新节点[maxsize];
for(int i=0;i queryEnd){
返回s;
}
int mid=mid(开始索引,结束索引);
Node left=getSumUtil(startIndex、mid、queryStart、queryEnd、leftchild(当前));
Node right=getSumUtil(mid+1,endIndex,queryStart,queryEnd,righchild(当前));
节点当前_节点=新节点();
当前_Node.max=Math.max(left.max,right.max);
当前_Node.MaxL=Math.max(left.MaxL,left.sum+right.MaxL);
当前_Node.MaxR=Math.max(right.MaxR,right.sum+left.MaxR);
当前_Node.sum=left.sum+right.sum;
返回当前_节点;
}
公共int getMaxSum(int queryStart,int queryEnd){
if(queryStart<0 | | queryEnd>tree.length)
{System.out.println(“内部负片”);
返回Integer.MIN_值;
}
返回getMax(getSumUtil(STARTINDEX、ENDINDEX、queryStart、queryEnd、ROOT));
}
公共int getMax(节点r){
返回Math.max(Math.max(r.max,r.MaxL),Math.max(r.MaxR,r.sum));
}
公共int getFirst(){
返回树[0].MaxL;
}
}
公共静态void main(字符串[]args){
扫描仪输入=新扫描仪(System.in);
整数[]=新整数[input.nextInt()];
对于(int i=0;i您的方法是正确的,但是i/O速度对于这个问题也很重要,因为时间限制非常严格。您应该使用自定义阅读器,因为扫描仪
非常慢。
使用下面提到的类阅读输入
class Reader {
final private int BUFFER_SIZE = 1 << 16;private DataInputStream din;private byte[] buffer;private int bufferPointer, bytesRead;
public Reader(){din=new DataInputStream(System.in);buffer=new byte[BUFFER_SIZE];bufferPointer=bytesRead=0;
}public Reader(String file_name) throws IOException{din=new DataInputStream(new FileInputStream(file_name));buffer=new byte[BUFFER_SIZE];bufferPointer=bytesRead=0;
}public String readLine() throws IOException{byte[] buf=new byte[64];int cnt=0,c;while((c=read())!=-1){if(c=='\n')break;buf[cnt++]=(byte)c;}return new String(buf,0,cnt);
}public int nextInt() throws IOException{int ret=0;byte c=read();while(c<=' ')c=read();boolean neg=(c=='-');if(neg)c=read();do{ret=ret*10+c-'0';}while((c=read())>='0'&&c<='9');if(neg)return -ret;return ret;
}public long nextLong() throws IOException{long ret=0;byte c=read();while(c<=' ')c=read();boolean neg=(c=='-');if(neg)c=read();do{ret=ret*10+c-'0';}while((c=read())>='0'&&c<='9');if(neg)return -ret;return ret;
}public double nextDouble() throws IOException{double ret=0,div=1;byte c=read();while(c<=' ')c=read();boolean neg=(c=='-');if(neg)c = read();do {ret=ret*10+c-'0';}while((c=read())>='0'&&c<='9');if(c=='.')while((c=read())>='0'&&c<='9')ret+=(c-'0')/(div*=10);if(neg)return -ret;return ret;
}private void fillBuffer() throws IOException{bytesRead=din.read(buffer,bufferPointer=0,BUFFER_SIZE);if(bytesRead==-1)buffer[0]=-1;
}private byte read() throws IOException{if(bufferPointer==bytesRead)fillBuffer();return buffer[bufferPointer++];
}public void close() throws IOException{if(din==null) return;din.close();}
}
类读取器{
final private int BUFFER_SIZE=1您的算法的复杂度是多少?您是否尝试过在随机输入上运行它,并检查它需要多长时间?根据我的经验,您应该至少获得现代机器上时间限制的四分之一的运行时间,以便它在金字塔上传递。它在前8个测试用例中传递,但在第9个测试用例中失败,因此我很抱歉我认为第9个测试用例的输入量最大。我认为我的算法的复杂性是O(nlogn)@TheBear:我认为很少有人能用Java解决这一问题并非巧合。时间限制非常严格,因此如果你想坚持使用Java,可能需要大量的不断优化才能完成。也许可以使用数组来表示树(比如隐式堆)比一次分配每个节点更快。I/O速度可能也是一个问题,Scanner
的速度非常慢,这就是为什么人们通常使用自己的缓冲I/O整数解析例程进行竞争性编程的原因。@PhamTrung是的,你是对的,它应该是tree[current]。max=Math.max(left.max,Math.max(right.max,left.maxR+right.maxL));
我无法想象你不会在随机测试中发现这一点。当你不知道你的代码在什么情况下不起作用时,总是在SPOJ或类似网站上使用随机测试