线段树.docx
《线段树.docx》由会员分享,可在线阅读,更多相关《线段树.docx(25页珍藏版)》请在冰豆网上搜索。
线段树
单点更新:
最最基础的线段树,只更新叶子节点,然后把信息用PushUP(intr)这个函数更新上来
∙hdu1166敌兵布阵
∙题意:
O(-1)
∙思路:
O(-1)
线段树功能:
update:
单点增减query:
区间求和
1.#include
2.#include
3.
4.#define M 50005
5.#define lson l,m,rt<<1
6.#define rson m+1,r,rt<<1|1
7./*left,right,root,middle*/
8.
9.int sum[M<<2];
10.
11.inline void PushPlus(int rt)
12.{
13. sum[rt] = sum[rt<<1] + sum[rt<<1|1];
14.}
15.
16.void Build(int l, int r, int rt)
17.{
18. if(l == r)
19. {
20. scanf("%d", &sum[rt]);
21. return ;
22. }
23. int m = ( l + r )>>1;
24.
25. Build(lson);
26. Build(rson);
27. PushPlus(rt);
28.}
29.
30.void Updata(int p, int add, int l, int r, int rt)
31.{
32.
33. if( l == r )
34. {
35. sum[rt] += add;
36. return ;
37. }
38. int m = ( l + r ) >> 1;
39. if(p <= m)
40. Updata(p, add, lson);
41. else
42. Updata(p, add, rson);
43.
44. PushPlus(rt);
45.}
46.
47.int Query(int L,int R,int l,int r,int rt)
48.{
49. if( L <= l && r <= R )
50. {
51. return sum[rt];
52. }
53. int m = ( l + r ) >> 1;
54. int ans=0;
55. if(L<=m )
56. ans+=Query(L,R,lson);
57. if(R>m)
58. ans+=Query(L,R,rson);
59.
60. return ans;
61.}
62.int main()
63.{
64. int T, n, a, b;
65. scanf("%d",&T);
66. for( int i = 1; i <= T; ++i )
67. {
68. printf("Case %d:
\n",i);
69. scanf("%d",&n);
70. Build(1,n,1);
71.
72. char op[10];
73.
74. while( scanf("%s",op) &&op[0]!
='E' )
75. {
76.
77. scanf("%d %d", &a, &b);
78. if(op[0] == 'Q')
79. printf("%d\n",Query(a,b,1,n,1));
80. else if(op[0] == 'S')
81. Updata(a,-b,1,n,1);
82. else
83. Updata(a,b,1,n,1);
84.
85. }
86. }
87. return 0;
88.}
hdu1754IHateIt
题意:
O(-1)
思路:
O(-1)
线段树功能:
update:
单点替换query:
区间最值
[cpp] viewplain copy
print?
1.#include
2.#include
3.using namespace std;
4.
5.#define lson l , m , rt << 1
6.#define rson m + 1 , r , rt << 1 | 1
7.const int maxn = 222222;
8.int MAX[maxn<<2];
9.void PushUP(int rt) {
10. MAX[rt] = max(MAX[rt<<1] , MAX[rt<<1|1]);
11.}
12.void build(int l,int r,int rt) {
13. if (l == r) {
14. scanf("%d",&MAX[rt]);
15. return ;
16. }
17. int m = (l + r) >> 1;
18. build(lson);
19. build(rson);
20. PushUP(rt);
21.}
22.void update(int p,int sc,int l,int r,int rt) {
23. if (l == r) {
24. MAX[rt] = sc;
25. return ;
26. }
27. int m = (l + r) >> 1;
28. if (p <= m) update(p , sc , lson);
29. else update(p , sc , rson);
30. PushUP(rt);
31.}
32.int query(int L,int R,int l,int r,int rt) {
33. if (L <= l && r <= R) {
34. return MAX[rt];
35. }
36. int m = (l + r) >> 1;
37. int ret = 0;
38. if (L <= m) ret = max(ret , query(L , R , lson));
39. if (R > m) ret = max(ret , query(L , R , rson));
40. return ret;
41.}
42.int main() {
43. int n , m;
44. while (~scanf("%d%d",&n,&m)) {
45. build(1 , n , 1);
46. while (m --) {
47. char op[2];
48. int a , b;
49. scanf("%s%d%d",op,&a,&b);
50. if (op[0] == 'Q') printf("%d\n",query(a , b , 1 , n , 1));
51. else update(a , b , 1 , n , 1);
52. }
53. }
54. return 0;
55.}
hdu1394MinimumInversionNumber
如2431中,21,43,41,31是逆序,逆序数是4,为偶排列。
题意:
求Inversion后的最小逆序数
思路:
用O(nlogn)复杂度求出最初逆序数后,就可以用O
(1)的复杂度分别递推出其他解
线段树功能:
update:
单点增减query:
区间求和
[cpp] viewplain copy
print?
1.#include
2.#include
3.using namespace std;
4.
5.#define lson l , m , rt << 1
6.#define rson m + 1 , r , rt << 1 | 1
7.const int maxn = 5555;
8.int sum[maxn<<2];
9.void PushUP(int rt) {
10. sum[rt] = sum[rt<<1] + sum[rt<<1|1];
11.}
12.void build(int l,int r,int rt) {
13. sum[rt] = 0;
14. if (l == r) return ;
15. int m = (l + r) >> 1;
16. build(lson);
17. build(rson);
18.}
19.void update(int p,int l,int r,int rt) {
20. if (l == r) {
21. sum[rt] ++;
22. return ;
23. }
24. int m = (l + r) >> 1;
25. if (p <= m) update(p , lson);
26. else update(p , rson);
27. PushUP(rt);
28.}
29.int query(int L,int R,int l,int r,int rt) {
30. if (L <= l && r <= R) {
31. return sum[rt];
32. }
33. int m = (l + r) >> 1;
34. int ret = 0;
35. if (L <= m) ret += query(L , R , lson);
36. if (R > m) ret += query(L , R , rson);
37. return ret;
38.}
39.int x[maxn];
40.int main() {
41. int n;
42. while (~scanf("%d",&n)) {
43. build(0 , n - 1 , 1);
44. int sum = 0;
45. for (int i = 0 ; i < n ; i ++) {
46. scanf("%d",&x[i]);
47. sum += query(x[i] , n - 1 , 0 , n - 1 , 1);
48. update(x[i] , 0 , n - 1 , 1);
49. }
50. int ret = sum;
51. for (int i = 0 ; i < n ; i ++) {
52. sum += n - x[i] - x[i] - 1;
53. ret = min(ret , sum);
54. }
55. printf("%d\n",ret);
56. }
57. return 0;
58.}
hdu2795Billboard
题意:
h*w的木板,放进一些1*L的物品,求每次放空间能容纳且最上边的位子
思路:
每次找到最大值的位子,然后减去L
线段树功能:
query:
区间求最大值的位子(直接把update的操作在query里做了)
[cpp] viewplain copy
print?
用数的最下面的节点表示一层(即到最下面一层有n个节点就可以了),并且用这个节点的左或右的区间范围表示层数(子节点的左区间和右区间其实是相同的),这个思路很巧,我也是看了别人的题解才懂的
1.#include
2.#include
3.using namespace std;
4.
5.#define lson l , m , rt << 1
6.#define rson m + 1 , r , rt << 1 | 1
7.const int maxn = 222222;
8.int h , w , n;
9.int MAX[maxn<<2];
10.void PushUP(int rt) {
11. MAX[rt] = max(MAX[rt<<1] , MAX[rt<<1|1]);
12.}
13.void build(int l,int r,int rt) {
14. MAX[rt] = w;
15. if (l == r) return ;
16. int m = (l + r) >> 1;
17. build(lson);
18. build(rson);
19.}
20.int query(int x,int l,int r,int rt) {
21. if (l == r) {
22. MAX[rt] -= x;
23. return l;
24. }
25. int m = (l + r) >> 1;
26. int ret = (MAX[rt<<1] >= x) ?
query(x , lson) :
query(x , rson);
27. PushUP(rt);
28. return ret;
29.}
30.int main() {
31. while (~scanf("%d%d%d",&h,&w,&n)) {
32. if (h > n) h = n;
33. build(1 , h , 1);
34. while (n --) {
35. int x;
36. scanf("%d",&x);
37. if (MAX[1] < x) puts("-1");
38. else printf("%d\n",query(x , 1 , h , 1));
39. }
40. }
41. return 0;
42.}
成段更新(通常这对初学者来说是一道坎),需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候
hdu1698JustaHook
题意:
O(-1)
思路:
O(-1)
线段树功能:
update:
成段替换(由于只query一次总区间,所以可以直接输出1结点的信息)
[cpp] viewplain copy
print?
1.#include
2.#include
3.using namespace std;
4.
5.#define lson l , m , rt << 1
6.#define rson m + 1 , r , rt << 1 | 1
7.const int maxn = 111111;
8.int h , w , n;
9.int col[maxn<<2];
10.int sum[maxn<<2];
11.void PushUp(int rt) {
12. sum[rt] = sum[rt<<1] + sum[rt<<1|1];
13.}
14.void PushDown(int rt,int m) {
15. if (col[rt]) {
16. col[rt<<1] = col[rt<<1|1] = col[rt];
17. sum[rt<<1] = (m - (m >> 1)) * col[rt];
18. sum[rt<<1|1] = (m >> 1) * col[rt];
19. col[rt] = 0;
20. }
21.}
22.void build(int l,int r,int rt) {
23. col[rt] = 0;
24. sum[rt] = 1;
25. if (l == r) return ;
26. int m = (l + r) >> 1;
27. build(lson);
28. build(rson);
29. PushUp(rt);
30.}
31.void update(int L,int R,int c,int l,int r,int rt) {
32. if (L <= l && r <= R) {
33. col[rt] = c;
34. sum[rt] = c * (r - l + 1);
35. return ;
36. }
37. PushDown(rt , r - l + 1);
38. int m = (l + r) >> 1;
39. if (L <= m) update(L , R , c , lson);
40. if (R > m) update(L , R , c , rson);
41. PushUp(rt);
42.}
43.int main() {
44. int T , n , m;
45. scanf("%d",&T);
46. for (int cas = 1 ; cas <= T ; cas ++) {
47. scanf("%d%d",&n,&m);
48. build(1 , n , 1);
49. while (m --) {
50. int a , b , c;
51. scanf("%d%d%d",&a,&b,&c);
52. update(a , b , c , 1 , n , 1);
53. }
54. printf("Case %d:
The total value of the hook is %d.\n",cas , sum[1]);
55. }
56. return 0;
57.}
poj3468ASimpleProblemwithIntegers
题意:
O(-1)
思路:
O(-1)
线段树功能:
update:
成段增减query:
区间求和
[cpp] viewplain copy
print?
1.#include
2.#include
3.using namespace std;
4.
5.#define lson l , m , rt << 1
6.#define rson m + 1 , r , rt << 1 | 1
7.#define LL long long
8.const int maxn = 111111;
9.LL add[maxn<<2];
10.LL sum[maxn<<2];
11.void PushUp(int rt) {
12. sum[rt] = sum[rt<<1] + sum[rt<<1|1];
13.}
14.void PushDown(int rt,int m) {
15. if (add[rt]) {
16. add[rt<<1] += add[rt];
17. add[rt<<1|1] += add[rt];
18. sum[rt<<1] += add[rt] * (m - (m >> 1));
19. sum[rt<<1|1] += add[rt] * (m >> 1);
20.