poj-1442

#include
#include
#include

#define HEAP_SIZE 30010

template
class Less {
public:
    char operator()(const T & p1, const T & p2) const {
        return p1 < p2;
    }
};

template
class More {
public:
    char operator()(const T & p1, const T & p2) const {
        return p1 > p2;
    }
};

template
class heap {
private:
    T mArray[HEAP_SIZE];
    C mCmp;
    int mHeapLength;

    int getLeftChildPos(int pos) {
        return pos*2 + 1;
    }

    int getRightChildPos(int pos) {
        return pos*2 + 2;
    }

    int getParentPos(int pos) {
        return (pos-1)/2;
    }


    void adjustHeapAfterPush() {
        int currentPos = mHeapLength - 1;
        int parentPos = getParentPos(currentPos);
        // printf("%d %d\n", currentPos, parentPos);
        while(1) {
            if (currentPos == 0) {
                break;
            }
            if (mCmp(mArray[currentPos], mArray[parentPos])) {
                T tmp = mArray[currentPos];
                mArray[currentPos] = mArray[parentPos];
                mArray[parentPos] = tmp;
                currentPos = parentPos;
                parentPos = getParentPos(currentPos);
            } else {
                break;
            }
        }
    }

public:
    void heapify(int Pos) {
        int leftChildPos = getLeftChildPos(Pos);
        int rightChildPos = getRightChildPos(Pos);

        int max = Pos;
        if (rightChildPos + 1 <= mHeapLength) {
            max = mCmp(mArray[rightChildPos], mArray[Pos]) ? rightChildPos : Pos;
        }
        if (leftChildPos + 1 <= mHeapLength) {
            max = mCmp(mArray[leftChildPos], mArray[max]) ? leftChildPos : max;
        }
        if (max == Pos) {
            return;
        } else {
            T tmp = mArray[Pos];
            mArray[Pos] = mArray[max];
            mArray[max] = tmp;
            heapify(max);
        }

    }

    void reset() {
        mHeapLength = 0;
        memset(mArray, 0, sizeof(mArray));
    }

    heap(C cmp): mCmp(cmp), mHeapLength(0) {
        memset(mArray, 0, sizeof(mArray));
    }

    void push(T p1) {
        mArray[mHeapLength++] = p1;
        adjustHeapAfterPush();
    }

    T top() {
        if (mHeapLength) {
            return mArray[0];        
        }
        return mArray[0];
    }

    void pop() {
        mArray[0] = mArray[--mHeapLength];
        heapify(0);
    }

    int size() {
        return mHeapLength;
    }

    void printArray() {
        printf("Array ");
        for (int i = 0; i < mHeapLength; i++) {
            printf("%ld ", mArray[i]);
        }
        printf("\n");
    }

    void setTop(T p1) {
        mArray[0] = p1;
        heapify(0);
    }

};

Less lessCmp;
More moreCmp;
heap > heapLess(lessCmp);
heap > heapMore(moreCmp);

long MArray[HEAP_SIZE];
long NArray[HEAP_SIZE];

void test() {
    Less lessCmp;
    More moreCmp;
    heap > heap1(lessCmp);
    heap > heap2(moreCmp);
    
    heapLess.push(3);
    // printf("%ld\n", heap1.top());
    heapLess.push(1);
    // printf("%ld\n", heap1.top());
    heapLess.push(-4);
    // printf("%ld\n", heap1.top());
    heapLess.push(2);
    // heap1.printArray();
    // printf("%ld\n", heap1.top());
    heapLess.push(8);
    // heap1.printArray();
    // printf("%ld\n", heap1.top());
    // heapLess.push(-1000);
    // // printf("%ld\n", heap1.top());
    // heapLess.push(190);
    // // printf("%ld\n", heap1.top());
    // heapLess.push(-3);
    // // printf("%ld\n", heap1.top());

    // heapLess.setTop(-199);
    heapLess.printArray();

    heapMore.push(100);
    heapMore.push(1);
    heapMore.push(98);
    heapMore.push(12);
    heapMore.push(43);
    heapMore.push(56);
    heapMore.push(190);
    heapMore.push(-3);
    printf("LESS\n");
    while(heapLess.size()) {
        printf("%ld\n", heapLess.top());
        heapLess.pop();
    }

    printf("MORE\n");
    while(heapMore.size()) {
        printf("%ld\n", heapMore.top());
        heapMore.pop();
    }
}


void printRes(int M, int N) {
    int i = 0;
    int Mbegin = 0;
    for (int i = 0; i < N; i++) {
        if (Mbegin < NArray[i]) {
            for(int j = Mbegin; j < NArray[i]; j++) {
                // printf("FOR %d %ld\n", Mbegin, NArray[i]);
                if (heapMore.size() >= i+1) {
                    // printf("1 %d %d\n", heapMore.size(), i);
                    if (heapMore.top() > MArray[j]) {
                        heapLess.push(heapMore.top());
                        heapMore.setTop(MArray[j]);
                    } else {
                        heapLess.push(MArray[j]);
                    }
                } else {
                    if (!heapMore.size()) {
                        // printf("1 heapMore.push %ld\n", MArray[j]);
                        heapMore.push(MArray[j]);
                    } else if (heapLess.size() && heapLess.top() < MArray[j]) {
                        // printf("2 heapMore.push %ld\n", MArray[j]);
                        heapMore.push(heapLess.top());
                        heapLess.setTop(MArray[j]);
                    } else {
                        // printf("3 heapMore.push %ld i %d size %d\n", MArray[j], i, heapMore.size());
                        heapMore.push(MArray[j]);
                    }
                }
            }
            Mbegin = NArray[i];
        } else {
            heapMore.push(heapLess.top());
            heapLess.pop();
        }
        // heapLess.printArray();
        // heapMore.printArray();
        printf("%ld\n", heapMore.top());
    }
}

int main() {
    // test();
    heapLess.reset();
    heapMore.reset();
    memset(MArray, 0, sizeof(MArray));
    memset(NArray, 0, sizeof(NArray));
    int M;
    int N;
    scanf("%d %d", &M, &N);
    for (int i = 0; i < M; i++) {
        scanf("%ld", MArray + i);
    }
    for (int i = 0; i < N; i++) {
        scanf("%ld", NArray + i);
    }

    printRes(M, N);
}


G++ 832K 313MS.

本质是一个求第k大的问题,之前也遇到过,当时用了算导上的逐步逼近法解的。

这次题目特殊,要求在数组的不断扩展中求第1,2... N大的数,显然,每次扩展完直接排序或者逐步逼近求出第k大铁定要TLE的。

后来看了提示,才知道可以用一个大顶堆和一个小顶堆解决,这个解法要牢记,其实单独的求第k大的数,有一个大顶/小顶堆就足够了,比如要求第k大的数,

那么就搞一个从容量为k的大顶堆,然后顺序往里满塞数组元素,当大顶堆被塞满时,再进入的元素就和大顶堆的堆顶元素(堆中最大)进行比较,如果比堆顶还大,直接pass, 如果比堆顶小,那么替换堆顶为此新元素,然后调整堆,这样最后遍历完元素以后,大顶堆的堆顶就是数组的第k大元素(当然,数组本身必须有>=k个元素)。

堆在有些大数据处理题里面用的也挺多,堆在这里的运用本质类似于筛子,不过这个筛子是固定容量,并且筛选标准不断的在紧缩。

这道题用两个堆的原因是因为该题是不断在顺序的求第1,2,3...k大元素,而每个求第k大的过程中,数组元素可能会有增加,如果只用一个堆,每次重新开始求数组的第k大,

显然效率低,没有充分利用之前的信息。

所以需要两个堆(maxheap minheap),在已经加入了N个元素时(第N步),在第i次GET第i大数组元素时,大顶堆(因为题目要求是求第i “大” 的,因此用大顶)负责保存数组前i大个元素,堆顶就是第i大的元素,而另一个堆,小顶堆则负责存储剩余的第i+1~N个元素,堆顶为这一堆元素中最小的元素(小顶)。

然后再假设第i+1次GET是在加入了M个元素之后(第M步),那么,在这M个元素的添加过程中,首先为了能在第i+1步的时候直接从maxheap的堆顶直接拿到,那么在每次的添加元素时,要做以下的处理:

case1: maxheap的元素个数不到 i +1, 没有填满,那么就拿新元素new和minheap的堆顶进行比较,如果new比minheap堆顶还小,那么必然new小于minheap的每个元素,

而maxheap则需要添加一个new与minheap元素群中的最小元素(不然就不满足第i+1大了,因为minheap有比其还小的),那么就将此元素直接加到maxheap里,并且要调整堆(new不保证比maxheap每个都小)。

case2: 同case1, 但是new比minheap堆顶大,那么将minheap堆顶加入到maxheap,而将new再加入maxheap。

case3:maxheap的元素已经填满了,new比maxheap的堆顶要小,将maxheap堆顶去掉,加到minheap中,将new加入maxheap。

case4:同case3,但是new>=堆顶, 那么直接加入minheap。

特殊case1:,在一个ADD之后,紧接来了几次GET, 这种情况下,不会有新元素加入,要进行的操作就是不断的把minheap的堆顶挪到maxheap中,maxheap堆顶就是要求第k大.

特殊case2:  在将new与min/maxheap堆顶比较时, 要考虑minheap和maxheap为空的情况。

这道题在知道解法以后也不是很好写,再次感受到了自己在行动和思维上的差距,自己写的堆又在求parentPos的时候多了-1,而后面在一条条的ADD GET指令的交叉执行中,

又是险象环生。不过也有了些开悟,纵观自己coding这些年,涉及到比较复杂的逻辑,有一点是我做的很差的,及为每个变量和函数赋予决定精确和合适的含义(不是指命名),在写code时,经常对某个变量的真正作用与定位认识糢糊,最普遍的就是+/-1的问题,就是因为定位不准. 这是一个痛点,以前会绕开,以目的为导向,不过这次一定要下决心解决这个痛点,bypass最终败给勇往直前.

你可能感兴趣的:(POJ)