POJ 3580 - SuperMemo 解題心得( 題目 )

解題概念:treap

解題方法:這題得使用特殊資料結構,像是segment tree不支持插入,而linkedlist先不考慮查詢,刪除速度也夠慢,所以這題必須使用treap,讓所有操作為O(logN)才行,我們使用無旋式treap。

INSERT:把treap切開,插入一個新的點再和回去

DELETE:把treap切開,切成3份,中間那份為移除的那個,把左右和回去

MIN:把treap切成三份,中間那份為查詢區間,進行MIN更新後取頂端。

ADD:把treap切成三份,在中間那份頂端打加值懶標

REVERSE:把treap切成三份,在中間那份頂端打反轉懶標

REVOLVE:把treap切成四份(觀察規律),把二、三部分交換。

Java參考程式碼(更好意見可留言於下方,謝謝!):

//Author:En Chi Tsung(欉恩祁)

//Date:2022/03/02

import java.io.*;

import java.util.*;

public class Main {

    public static int tem;

    public static Treap a;

    public static Treap[] x,y,z;

    public static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

    public static BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));    

    public static void main(String[] args) throws Exception{

        String[] in=br.readLine().split(" ");

        final int n=Integer.parseInt(in[0]);

        a=null;

        for(int i=0;i<n;i++) {

            in=br.readLine().split(" ");

            a=Merge(a,new Treap(Long.parseLong(in[0])));

        }

        in=br.readLine().split(" ");

        final int m=Integer.parseInt(in[0]);

        int l,r,t;

        long v;

        for(int i=0;i<m;i++) {

            in=br.readLine().split(" ");

            if(in[0].equals("ADD")) {

                l=Integer.parseInt(in[1]);

                r=Integer.parseInt(in[2]);

                v=Long.parseLong(in[3]);

                Add(l,r,v);

            }

            if(in[0].equals("REVERSE")) {

                l=Integer.parseInt(in[1]);

                r=Integer.parseInt(in[2]);

                Reverse(l,r);

            }


            if(in[0].equals("REVOLVE")) {

                l=Integer.parseInt(in[1]);

                r=Integer.parseInt(in[2]);

                v=Long.parseLong(in[3]);

                Revolve(l,r,v);

            }

            if(in[0].equals("INSERT")) {

                l=Integer.parseInt(in[1]);

                v=Long.parseLong(in[2]);

                Insert(l,v);

            }


            if(in[0].equals("DELETE")) {

                t=Integer.parseInt(in[1]);

                Delete(t);

            }

            if(in[0].equals("MIN")) {

                l=Integer.parseInt(in[1]);

                r=Integer.parseInt(in[2]);

                Query(l,r);

            }    

        }

        bw.flush();

    }

    

    public static void Add(int l,int r,long v){

        x=Split(a,r);

        y=Split(x[0],l-1);

        y[1].val+=v;

        y[1].min+=v;

        y[1].lt+=v;

        a=Merge(Merge(y[0],y[1]),x[1]);

    }

    

    public static void Reverse(int l,int r){

        x=Split(a,r);

        y=Split(x[0],l-1);

        if(y[1]!=null)y[1].rev^=1;

          a=Merge(Merge(y[0],y[1]),x[1]);

    }

    

    public static void Revolve(int l,int r,long t) {

        x=Split(a,r);

        y=Split(x[0],l-1);

        if(t<0) {

            t+=((-t*(r-l+1)/(r-l+1))+1);

        }

        z=Split(y[1],(int)(r-l+1-t%(r-l+1)));

        a=Merge(Merge(y[0],Merge(z[1],z[0])),x[1]);

    }

    

    public static void Insert(int l,long v) throws Exception{

        x=Split(a,l);

        a=Merge(Merge(x[0],new Treap(v)),x[1]);

    }

    

    public static void Delete(int l) throws Exception{

        x=Split(a,l);

        y=Split(x[0],l-1);

        a=Merge(y[0],x[1]);

    }

    

    public static void Query(int l,int r) throws Exception{

        x=Split(a,r);

        y=Split(x[0],l-1);

        bw.write(y[1].min+"\n");

        a=Merge(Merge(y[0],y[1]),x[1]);

    }

    

    public static Treap Merge(Treap a,Treap b) {

        if(a==null)return b;

        if(b==null)return a;

        a.Move();

        b.Move();

        if(a.pri<b.pri) {

            a.tr[1]=Merge(a.tr[1],b);

            if(a!=null)a.Reset();

            return a;

        }

        else {

            b.tr[0]=Merge(a,b.tr[0]);

            if(b!=null)b.Reset();

            return b;

        }

    }

    

    public static Treap[] Split(Treap a,int L) {

        if(a==null)return new Treap[] {null,null};

        a.Move();

        if(L<=((a.tr[0]==null)?0:a.tr[0].size)) {

            Treap[] left=Split(a.tr[0],L);

            a.tr[0]=left[1];

            if(a!=null)a.Reset();

            return new Treap[] {left[0],a};

        }

        else {

            Treap[] right=Split(a.tr[1],L-((a.tr[0]==null)?0:a.tr[0].size)-1);

            a.tr[1]=right[0];

            if(a!=null)a.Reset();

            return new Treap[] {a,right[1]};

        }

    }

}





class Treap{

    long val,lt=0,min=(1<<30);

    int pri,size=1,rev=0;

    Treap[] tr=new Treap[2];

    Treap(long v){

        val=min=v;

        pri=(int)(Math.random()*1000000000);

    }

    

    void Reset() {

        if(this==null)return;

        size=1;

        min=val;

        if(tr[0]!=null) {

            min=Math.min(min,tr[0].min);

            size+=tr[0].size;

        }

        if(tr[1]!=null) {

            min=Math.min(min,tr[1].min);

            size+=tr[1].size;

        }

    }

    

    void Move() {

        if(this==null)return;

        if(lt!=0) {

            if(tr[0]!=null) {

                tr[0].lt+=lt;

                tr[0].min+=lt;

                tr[0].val+=lt;

            }

            if(tr[1]!=null) {

                tr[1].lt+=lt;

                tr[1].min+=lt;

                tr[1].val+=lt;

            }

            lt=0;

        }

        if(rev!=0) {

            rev=0;

            if(tr[0]!=null) {

                tr[0].rev^=1;

            }

            if(tr[1]!=null) {

                tr[1].rev^=1;

            }

            Treap temp=tr[0];

            tr[0]=tr[1];

            tr[1]=temp;

         }

    }

}

 

 

 

 

arrow
arrow

    En Chi Tsung 發表在 痞客邦 留言(0) 人氣()