现在的位置: 首页 > 综合 > 正文

NOI 2010 超级钢琴

2014年01月14日 ⁄ 综合 ⁄ 共 2341字 ⁄ 字号 评论关闭

晚上发现NOI不给用优先级队列,就自己写个堆,还行,速度

#include <cstdio>
const int N = (500000 + 1234) * 2;

struct heap_node
{
    int value, l, r, minv, loc;
    heap_node(int v1,int l1,int r1,int minv1, int loc1)
    {
        value = v1;
        l = l1;
        r = r1;
        minv = minv1;
        loc = loc1;
    }
    heap_node() {}
};


void swap(int& a, int& b)
{
    int temp = a;
    a = b;
    b = temp;
}

int max(int a, int b)
{
    if(a > b)  return a;
    return b;
}

//int mark;
class Heap
{
public:
    int size;
    int heap[N];
    int l[N], r[N], minv[N], loc[N];
    void init()
    {
        size=0;
        heap[0]=1<<30;
    }
    void adjust(int i)
    {
        int j;
        if (heap[i]>heap[i>>1])
        {
            for ( ; heap[i]>heap[i>>1]; i=j)
            {
                j=i>>1;
                //if(j == 0)  break;
                swap(heap[i], heap[j]);
                swap(l[i], l[j]);
                swap(r[i], r[j]);
                swap(minv[i], minv[j]);
                swap(loc[i], loc[j]);
            }
            //mark = i;
        }
        else
        {
            for (j=i; ; i=j)
            {
                if ((i<<1)<=size && heap[j]<heap[i<<1] )
                    j=i<<1;
                if ( (i<<1)+1<=size && heap[j]<heap[(i<<1)+1] )
                    j=(i<<1)+1;
                if (j==i) break;
                swap(heap[i], heap[j]);
                swap(l[i], l[j]);
                swap(r[i], r[j]);
                swap(minv[i], minv[j]);
                swap(loc[i], loc[j]);
            }
            //mark = i;
        }
    }
    void push(heap_node c)
    {
        ++size;
        heap[size]=c.value;
        l[size] = c.l;
        r[size] = c.r;
        minv[size] = c.minv;
        loc[size] = c.loc;
        adjust(size);
    }
    heap_node pop()
    {
        swap(heap[1], heap[size]);
        swap(l[1], l[size]);
        swap(r[1], r[size]);
        swap(minv[1], minv[size]);
        swap(loc[1], loc[size]);
        if (--size) adjust(1);
        heap_node t(heap[size+1], l[size+1], r[size+1], minv[size+1], loc[size+1]);
        return t;
    }
} hp;

int st[19][500001];//RMQ是用的数组
int s[500001], log[500001];

int Query_RMQ(int a, int b)
{
    int loc = log[b-a+1];//2的多少次方
    if (s[st[loc][a]] < s[st[loc][b-(1<<loc)+1]])
        return st[loc][a];
    else
        return st[loc][b-(1<<loc)+1];
}

int main()
{
   // freopen("piano5.in","r",stdin);
    int n, k, L, R, i, j, x, minv, t1, t2;
    long long ans;
    heap_node tmp;

    scanf("%d%d%d%d", &n, &k, &L, &R);
    for (s[0] = 0, i = 1; i <= n; i ++) //前缀和
        scanf("%d", &x), s[i] = s[i-1] + x;

    for (log[1] = 0, i = 2; i <= n; i ++)
        log[i] = log[i-1] + ((i & -i) == i);

    for (i = 1; i <= n; i ++) st[0][i] = i - 1;
    for (i = 1; 1 << i <= n; i ++)
        for (j = 1; j + (1 << i) - 1 <= n; j ++)
            if (s[st[i-1][j]] < s[st[i-1][j+(1<<i-1)]])
                st[i][j] = st[i-1][j];
            else
                st[i][j] = st[i-1][j+(1<<i-1)];

    hp.init();
    for (i = L; i <= n; i ++)
    {
        t1 = max(1, i - R + 1), t2 = i - L + 1;//找到左端点所在的区间
        minv = Query_RMQ(t1, t2);
        heap_node t(s[i] - s[minv], t1, t2, minv + 1, i);
        //和,左端点所在的区间两个端点,最小值所在的序号,右端点
        hp.push(t);
        //if(i==351288) printf("mark=%d\n",mark);
    }

    for (ans = 0, i = 1; i <= k; i ++)
    {
        tmp = hp.pop();
        ans += tmp.value;
        if (tmp.l < tmp.minv)
        {
            t1 = tmp.l, t2 = tmp.minv - 1;
            minv = Query_RMQ(t1, t2);
            heap_node t(s[tmp.loc] - s[minv], t1, t2, minv + 1, tmp.loc);
            hp.push(t);
        }
        if (tmp.minv < tmp.r)
        {
            t1 = tmp.minv + 1, t2 = tmp.r;
            minv = Query_RMQ(t1, t2);
            heap_node t(s[tmp.loc] - s[minv], t1, t2, minv + 1, tmp.loc);
            hp.push(t);
        }
    }

    printf("%I64d\n", ans);
    return 0;
}

抱歉!评论已关闭.