线段树、优先队列、单调队列小结
原文转自:http://blog.csdn.net/lhshaoren/article/details/7897736
主要处理问题:
线段树:区间处理,一般需要对整个区间执行相同的操作,时间复杂度O(log(n))
优先队列:堆实现,找出最小或最大元素,或者第k小或第k大元素,一般区间内元素个数不变,只有个别元素会发生变化。时间复杂度O(log(n))
单调队列:设队列中元素从小到大,则如果要插入元素比队尾大,则直接入队。如果比队尾小,则队尾元素出队,直到发现队尾不比插入元素小或者队为空,再入队。
有规律的更新区间内元素,需要判定队头元素是否符合条件。可以处理最小或最大问题,或者第k小或第k大问题。时间复杂度O(n)
线段树模板:
- //求区间内最大值
- struct Node
- {
- int l, r;
- int _max;
- Node(){}
- Node(int l, int r, int _max): l(l), r(r), _max(_max){}
- }node[nMax * 4];
- int A[nMax];
- int fmax(int a, int b)
- {
- return a > b ? a : b;
- }
- void build(int rt, int l, int r)//创建
- {
- if(l < r)
- {
- int mid = (l + r) / 2;
- build(rt * 2, l, mid);
- build(rt * 2 + 1, mid + 1, r);
- int _max = fmax(node[rt * 2]._max, node[rt * 2 + 1]._max);
- node[rt] = Node(l, r, _max);
- }
- else if(l == r)
- node[rt] = Node(l, r, A[l]);
- }
- void search(int rt, int l, int r, int &_max)//查询
- {
- if(node[rt].l == l && node[rt].r == r)
- _max = node[rt]._max;
- else
- {
- int mid = (node[rt].l + node[rt].r) / 2;
- if(mid >= r)
- search(rt * 2, l, r, _max);
- else if(mid + 1 <= l)
- search(rt * 2 + 1, l, r, _max);
- else
- {
- int max1, max2;
- search(rt * 2, l, mid, max1);
- search(rt * 2 + 1, mid + 1, r, max2);
- _max = fmax(max1, max2);
- }
- }
- }
- void update(int rt, int a, int b)//更新
- {
- if(node[rt].l == node[rt].r)
- node[rt]._max = b;
- else
- {
- int mid = (node[rt].l + node[rt].r) / 2;
- if(mid >= a)
- update(rt * 2, a, b);
- else if(mid + 1 <= a)
- update(rt * 2 + 1, a, b);
- node[rt]._max = fmax(node[rt * 2]._max, node[rt * 2 + 1]._max);
- }
- }
优先队列模板:
- //小顶堆
- int queue[nMax];
- int N;//总结点数
- queue[i] = w;//首先对最后一个节点赋值
- void build(int pos)
- {
- int p = pos;
- while(p != 1)
- {
- if(queue[p / 2] > queue[p])
- {
- int temp = queue[p / 2];
- queue[p / 2] = queue[p];
- queue[p] = temp;
- }
- else
- break;
- p = p / 2;
- }
- }
- queue[1] = w;//对顶点进行新的赋值操作
- void update()
- {
- int p = 1;
- int son;
- while(2 * p <= N)
- {
- if(2 * p == N || queue[2 * p] < queue[2 * p + 1])
- son = 2 * p;
- else
- son = 2 * p + 1;
- if(queue[son] < queue[p])
- {
- int temp = queue[son];
- queue[son] = queue[p];
- queue[p] = temp;
- }
- else
- break;
- p = son;
- }
- }
单调队列模板:
- //每次取出k个连续元素中最小值
- struct Queue
- {
- int pos;
- int w;
- Queue(){}
- Queue(int pos, int w): pos(pos), w(w){}
- }queue[nMax];
- int N, K;
- void update()
- {
- int front, rear;
- front = rear = 0;
- int i;
- for(i = 1; i <= N; ++ i)
- {
- while(front != rear && queue[front - 1].w > A[i]) front --;//入队
- queue[front ++] = Queue(i, A[i]);
- if(i >= K)
- {
- while(queue[rear].pos <= i - K)//排除
- rear ++;
- printf("%d ", queue[rear]);//取出数据
- }
- }
- }