【问题标题】:GSS1 -SPOJ - Segment tree TLEGSS1 -SPOJ - 段树 TLE
【发布时间】:2014-04-29 23:57:13
【问题描述】:

我正在使用线段树解决this problem。我在每个节点保存总和、最大值、最左边的最大值和最右边的最大值。然后我搜索图表以找到特定区间的答案。我怎样才能提高这段代码的速度?

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));
    }






    }

}

【问题讨论】:

  • 你的算法的复杂度是多少?您是否尝试过在随机输入上运行它并检查需要多长时间?根据我的经验,您应该至少获得现代机器时间限制的四分之一的运行时间,以便它通过 Pyramid
  • 它通过前 8 个测试用例,但在第九个测试用例失败,所以我假设第 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 或类似网站上使用随机测试

标签: java algorithm optimization segment-tree


【解决方案1】:

您的方法是正确的,但 I/O 速度对于这个问题也很重要,因为时序限制非常严格。您应该使用自定义阅读器,因为 Scanner 非常慢。 使用下面提到的类来读取输入。

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();}
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 1970-01-01
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    • 2023-04-02
    相关资源
    最近更新 更多