题意:
给出一些人要求插入队列的位置和他们的身高
输出最后队列的每个人身高
输入:
给出n 表示有n个人
给出每个人要插进的队列的位置和该人的身高
思路:
sum 数组保存该区间的空位
a 数组保存该位置的人的身高
pushup函数用来自下向上更新区间空位
modify函数用来根据sum值找出空位并插入..
Tips:
比较的时候..如果比左节点的sum值大就往右子树插位置..
所以比较函数写的应该是..if(p <= sum[rt<<1])
往右子树插的时候传入的参数也应该相应减少..即p - sum[rt<<1]
Code:
1 //模拟链表 数据量太大..遍历会超时.. 2 #include <stdio.h> 3 #include <cstring> 4 using namespace std; 5 6 const int MAXN = 200010; 7 int a[MAXN], sum[MAXN<<2]; 8 9 struct P 10 { 11 int key; 12 int val; 13 }pp[MAXN]; 14 15 void pushup(int rt) 16 { 17 sum[rt] = sum[rt<<1]+sum[rt<<1|1]; 18 } 19 20 void creat(int l, int r, int rt) 21 { 22 if(l == r) { 23 sum[rt] = 1; 24 return; 25 } 26 int mid = (l+r)>>1; 27 creat(l, mid, rt<<1); 28 creat(mid+1, r, rt<<1|1); 29 pushup(rt); 30 } 31 32 void modify(int p, int w, int l, int r, int rt) 33 { 34 if(l == r) { 35 sum[rt]--; 36 a[l] = w; 37 return; 38 } 39 int mid = (l+r)>>1; 40 if(p <= sum[rt<<1]) modify(p, w, l, mid, rt<<1);///!!! 41 else modify(p - sum[rt<<1], w, mid+1, r, rt<<1|1);///!!! 42 pushup(rt); 43 } 44 45 int main() 46 { 47 int i, j, k; 48 int n, val, key; 49 while(scanf("%d", &n) != EOF) 50 { 51 creat(1, n, 1); 52 53 for(i = 0; i < n; ++i) 54 scanf("%d %d", &pp[i].key, &pp[i].val); 55 56 for(i = n-1; i >= 0; --i) { 57 modify(pp[i].key+1, pp[i].val, 1, n, 1); 58 } 59 60 for(i = 1; i <= n; ++i) 61 printf("%d%c", a[i], i == n?'\n':' '); 62 } 63 return 0; 64 }
题目链接:http://poj.org/problem?id=2828
线段树基础总结:
确定四个函数 两个数组
※四个函数
void pushup(int rt) 自下向上更新线段树 sum数组是用来求和呢 还是 求最大值
void creat(int l, int r, int rt) 创建线段树 其中 r 的大小应该以最大可能出现的数的个数为准..
如果是初始化数组则第一句为初始化数组 第二句为 l == r 就 return
void modify(int p, int w, int l, int r, int rt) 把线段树更新.. 第一条的 if 语句用来更新线段树的叶子节点的值..并进行相关操作..
注意比较的时候是和 mid 比较呢还是和sum[rt<<1]比较 即使是根据位置更新节点 还是 根据区间值更新节点..
void query(int l, int r, int L, int R, int rt) 查询线段树某一区间的值..最大值或和..
两个数组..
sum 保存线段树节点的值.. 所以要考虑这棵树究竟保留的是什么信息..
a 保存的是叶子节点的相关信息..
变形:
①. 求区间和
②. 求区间最大值
③. 求逆序数(区间求和变形) 根据插入顺序更新sum数组 并且查询从该位置到最后已标记的位置的数量
④. 求一些区间中最大的区间长度(区间最大值变形) 判断的时候应该是和sum[rt << 1] 比较..然后看往哪里更新..