地主毛毛有n座山,这些山在地主家门前排成一条直线。这些山一开始均有相同的高度。  每一天,毛毛都会要求花花开挖机把几座山挖掉一定高度,或者给一些山堆上一些高度。并且要求花花报告现在有多少座山属于“高山脉”
当一排山的高度相等,并且比这排山左边和右边的山要高时,这排山被称为高山脉。
当然,最左边和最右边的山不可能是“高山脉”的一部分
 

这题乍一看可以用线段树做,事实上确实可以用线段树做,但是在仔细思考,讨论出所有情况之后发现可以修改端点代替修改区间的方法来AC

也就是说,将每次修改的L和R变为修改单点,用一次solve来将L之后的所有山全部加上v,再用一次solve来将R + 1之后的山高度全部减去R,在修改的过程中利用map来修改ans可以实现题目要求的在线

1.map的AC代码

  1. #include <map>
  2. #include <set>
  3. #include <cmath>
  4. #include <queue>
  5. #include <stack>
  6. #include <vector>
  7. #include <string>
  8. #include <cstdio>
  9. #include <cstdlib>
  10. #include <cstring>
  11. #include <sstream>
  12. #include <iostream>
  13. #include <algorithm>
  14. #include <functional>
  15. #define For(i, x, y) for(int i=x; i<=y; i++)
  16. #define _For(i, x, y) for(int i=x; i>=y; i--)
  17. #define Mem(f, x) memset(f, x, sizeof(f))
  18. #define Sca(x) scanf("%d", &x)
  19. #define Scl(x) scanf("%lld",&x);
  20. #define Pri(x) printf("%d\n", x)
  21. #define Prl(x) printf("%lld\n",x);
  22. #define CLR(u) for(int i = 0; i <= N ; i ++) u[i].clear();
  23. #define LL long long
  24. #define ULL unsigned long long
  25. #define mp make_pair
  26. #define PII pair<int,int>
  27. #define PIL pair<int,long long>
  28. #define PLL pair<long long,long long>
  29. #define pb push_back
  30. #define fi first
  31. #define se second
  32. using namespace std;
  33. typedef vector<int> VI;
  34. const double eps = 1e-;
  35. const int maxn = ;
  36. const int INF = 0x3f3f3f3f;
  37. const int mod = 1e9 + ;
  38. inline int read()
  39. {
  40. int now=;register char c=getchar();
  41. for(;!isdigit(c);c=getchar());
  42. for(;isdigit(c);now=now*+c-'',c=getchar());
  43. return now;
  44. }
  45. int N,Q,R;
  46. int ans = ;
  47. map<int,int>P;
  48. void solve(int mid,int v){
  49. if(!v)return;
  50. map<int,int> ::iterator it,l,r;
  51. //cout << mid << " " << P[mid] <<endl;
  52. if(P[mid] == ){
  53. l = r = it = P.find(mid); //这一步要放在if里面
  54. l--,r++;
  55. if(l->se > && r->se > && v < ){
  56. ans += (mid - l->fi);
  57. // cout << l->fi << " " << it->fi << " " << r->fi << endl;
  58. }else if(l->se > && r->se < && v < ){
  59. ans -= (r->fi - mid);
  60. }else if(l->se < && r->se < && v > ){
  61. ans += (r->fi - mid);
  62. }else if(l->se > && r->se < && v > ){
  63. ans -= mid - l->fi;
  64. }
  65. P[mid] = v;
  66. }else{
  67. l = r = it = P.find(mid);
  68. l--,r++;
  69. if(r == P.end() || it == P.begin()) return; //对最左端和最右端的更新
  70. if(l->se > && r->se > && it->se < ){
  71. ans -= mid - l->fi;
  72. }else if(l->se < && r->se < && it->se > ){
  73. ans -= r->fi - mid;
  74. }else if(l->se > && r->se < && it->se < ){
  75. ans += r->fi - mid;
  76. }else if(l->se > && r->se < && it->se > ){
  77. ans += mid - l->fi;
  78. }
  79. // cout << it->fi << " " << it->se << endl;
  80. v += it->se;
  81. P.erase(it);
  82. solve(mid,v);
  83. }
  84. }
  85. int main()
  86. {
  87. while(~scanf("%d%d%d",&N,&Q,&R)){
  88. P.clear();
  89. P[] = -INF; P[N + ] = INF;
  90. ans = ;
  91. while(Q--){
  92. int l,r,v;
  93. scanf("%d%d%d",&l,&r,&v);
  94. l ^= ans; r ^= ans; v ^= ans;
  95. solve(l,v);
  96. solve(r + ,-v);
  97. Pri(ans);
  98. }
  99. }
  100. return ;
  101. }

2.有了以上的算法,从实现难度上来讲线段树就不算是最优解了,但是对练习线段树的写法也有一定意义,所以我用线段树也实现了一次。

由于N大到1e9次,就不能像普通线段树一样直接build建树,要通过动态加点,也就是说只开辟使用到的区间的空间,由于查询只有50000次,仅仅开辟使用的空间并不会导致mle,学习了一手动态线段树的写法,这就很舒服

这次线段树的难度主要在于pushup的实现上已经怎么想到维护的点,去维护什么东西,还有动态线段树的实现

以下是动态线段树的代码

  1. #include <map>
  2. #include <set>
  3. #include <cmath>
  4. #include <queue>
  5. #include <stack>
  6. #include <vector>
  7. #include <string>
  8. #include <cstdio>
  9. #include <cstdlib>
  10. #include <cstring>
  11. #include <sstream>
  12. #include <iostream>
  13. #include <algorithm>
  14. #include <functional>
  15. #define For(i, x, y) for(int i=x; i<=y; i++)
  16. #define _For(i, x, y) for(int i=x; i>=y; i--)
  17. #define Mem(f, x) memset(f, x, sizeof(f))
  18. #define Sca(x) scanf("%d", &x)
  19. #define Scl(x) scanf("%lld",&x);
  20. #define Pri(x) printf("%d\n", x)
  21. #define Prl(x) printf("%lld\n",x);
  22. #define CLR(u) for(int i = 0; i <= N ; i ++) u[i].clear();
  23. #define LL long long
  24. #define ULL unsigned long long
  25. #define mp make_pair
  26. #define PII pair<int,int>
  27. #define PIL pair<int,long long>
  28. #define PLL pair<long long,long long>
  29. #define pb push_back
  30. #define fi first
  31. #define se second
  32. using namespace std;
  33. typedef vector<int> VI;
  34. const double eps = 1e-;
  35. const int maxn = ;
  36. const int INF = 0x3f3f3f3f;
  37. const int mod = 1e9 + ;
  38. inline int read()
  39. {
  40. int now=;register char c=getchar();
  41. for(;!isdigit(c);c=getchar());
  42. for(;isdigit(c);now=now*+c-'',c=getchar());
  43. return now;
  44. }
  45. int ans;
  46. int N,Q,R;
  47. struct Tree{
  48. int lt,rt;
  49. int sum; //高山脉的数目
  50. int lsum,rsum; //左右起高度相同的山脉
  51. int lh,rh; //左右山脉的高度
  52. int ll,rr; //左右第一个不连续山脉的高度
  53. int lazy;
  54. void init(int l,int r){
  55. sum = lh = rh = ll = rr = lazy = lt = rt = ;
  56. lsum = rsum = r - l + ;
  57. }
  58. }tree[maxn * ];
  59. int tot;
  60. void check(int &t,int l,int r){
  61. if(t) return;
  62. t = ++tot;
  63. tree[t].init(l,r);
  64. if(l == ) tree[t].ll = INF;
  65. if(r == N) tree[t].rr = INF;
  66. }
  67. void add(int t,int val){
  68. tree[t].lazy += val;
  69. tree[t].ll += val; tree[t].rr += val;
  70. tree[t].lh += val; tree[t].rh += val;
  71. }
  72. void Pushdown(int t,int l,int r){
  73. if(tree[t].lazy){
  74. int m = (l + r) >> ;
  75. check(tree[t].lt,l,m);
  76. check(tree[t].rt,m + ,r);
  77. add(tree[t].rt,tree[t].lazy);
  78. add(tree[t].lt,tree[t].lazy);
  79. tree[t].lazy = ;
  80. }
  81. }
  82. void Pushup(int t,int l,int r){
  83. int m = (l + r) >> ;
  84. int lt = tree[t].lt;
  85. int rt = tree[t].rt;
  86. check(lt,l,m); check(rt,m + ,r);
  87. tree[t].sum = tree[lt].sum + tree[rt].sum;
  88. tree[t].lsum = tree[lt].lsum; tree[t].rsum = tree[rt].rsum;
  89. tree[t].lh = tree[lt].lh; tree[t].rh = tree[rt].rh;
  90. tree[t].ll = tree[lt].ll; tree[t].rr = tree[rt].rr;
  91. if(tree[lt].rh == tree[rt].lh){
  92. if(tree[lt].rh > tree[lt].rr && tree[rt].ll < tree[rt].lh){
  93. tree[t].sum += tree[lt].rsum + tree[rt].lsum;
  94. }
  95. if(tree[lt].rsum == m - l + ){
  96. tree[t].lsum += tree[rt].lsum;
  97. tree[t].ll = tree[rt].ll;
  98. }
  99. if(tree[rt].lsum == r - m){
  100. tree[t].rsum += tree[lt].rsum;
  101. tree[t].rr = tree[lt].rr;
  102. }
  103. }else{
  104. int lson = lt; int rson = rt;
  105. if(tree[lson].lsum == m - l + ){
  106. tree[t].ll = tree[rson].lh;
  107. }
  108. if(tree[lson].rh > tree[rson].lh && tree[lson].rh > tree[lson].rr){
  109. tree[t].sum += tree[lson].rsum;
  110. }
  111. if(tree[rson].rsum == r - m){
  112. tree[t].rr = tree[lson].rh;
  113. }
  114. if(tree[rson].lh > tree[lson].rh && tree[rson].lh > tree[rson].ll){
  115. tree[t].sum += tree[rson].lsum;
  116. }
  117. }
  118. }
  119. void update(int &t,int l,int r,int L,int R,int val){
  120. check(t,l,r);
  121. if(L <= l && r <= R){
  122. add(t,val);
  123. return;
  124. }
  125. Pushdown(t,l,r);
  126. int m = (l + r) >> ;
  127. if(L <= m) update(tree[t].lt,l,m,L,R,val);
  128. if(R > m) update(tree[t].rt,m + ,r,L,R,val);
  129. Pushup(t,l,r);
  130. }
  131. int main()
  132. {
  133. while(~scanf("%d%d%d",&N,&Q,&R)){
  134. ans = ;
  135. tot = ;
  136. int root = ;
  137. while(Q--){
  138. int l,r,val;
  139. scanf("%d%d%d",&l,&r,&val);
  140. l ^= ans; r ^= ans; val ^= ans;
  141. if(l > r) swap(l,r);
  142. update(root,,N,l,r,val);
  143. ans = tree[root].sum;
  144. Pri(ans);
  145. }
  146. }
  147. return ;
  148. }
 

HDU5367 思维map // 动态线段树的更多相关文章

  1. HDU1199 动态线段树 // 离散化

    附动态线段树AC代码 http://acm.hdu.edu.cn/showproblem.php?pid=1199 因为昨天做了一道动态线段树的缘故,今天遇到了这题没有限制范围的题就自然而然想到了动态 ...

  2. C. Okabe and Boxes 思维 模拟 or 线段树

    C. Okabe and Boxes 这个题目是一个有点思维的模拟,当时没有想到, 思维就是这个栈的排序这里,因为每次直接排序肯定会t的,所以不可以这么写,那怎么表示排序呢? 就是直接把栈清空,如果栈 ...

  3. CF666E Forensic Examination(后缀自动机+动态线段树)

    题意 给你一个串 $S$ 以及一个字符串数组 $T[1..m]$ , $q$ 次询问,每次问 $S$ 的子串 $S[p_l..p_r]$ 在 $T[l..r]$ 中的哪个串里的出现次数最多,并输出出现 ...

  4. Codeforces 916E(思维+dfs序+线段树+LCA)

    题面 传送门 题目大意:给定初始根节点为1的树,有3种操作 1.把根节点更换为r 2.将包含u,v的节点的最小子树(即lca(u,v)的子树)所有节点的值+x 3.查询v及其子树的值之和 分析 看到批 ...

  5. BZOJ3531 树剖 + 动态开点线段树

    https://www.lydsy.com/JudgeOnline/problem.php?id=3531 首先这题意要求树链上的最大值以及求和,其树链剖分的做法已经昭然若揭 问题在于这次的信息有宗教 ...

  6. 线段树动态开点——cf1045G

    只计算半径小的能看到的半径大的,因为如果计算半径大的看到半径小的,虽然q在其范围内,但是小的不一定能看到大的 那么我们将机器人按照半径降序排序 遍历一次,去查询在[x-r,x+r]范围的,智商在[q- ...

  7. dfs+线段树 zhrt的数据结构课

    zhrt的数据结构课 这个题目我觉得是一个有一点点思维的dfs+线段树 虽然说看起来可以用树链剖分写,但是这个题目时间卡了树剖 因为之前用树剖一直在写这个,所以一直想的是区间更新,想dfs+线段树,有 ...

  8. NBUT 1120 线段树

    input q n q行 F a b或者Q a b output face left face top face right 可以用map或者线段树做 //map #include<cstdio ...

  9. CodeForces 19D Points (线段树+set)

    D. Points time limit per test 2 seconds memory limit per test 256 megabytes input standard input out ...

随机推荐

  1. 《Linux内核设计与实现》读书笔记 18

    第十八章调试 18.1 准备开始 一个bug:大部分bug通常都不是行为可靠而且定义明确的 一个藏匿bug的内核版本:找出bug首先出现的版本 相关内核代码的知识和运气 18.2内核中的bug 可以有 ...

  2. HTML编码规则

    <!DOCTYPE html><!-- 为每一个HTML页面的第一行添加标准模式 --> <html lang="en-us"> <!-- ...

  3. 第三个Sprint冲刺第五天(燃尽图)

  4. Beta 总结

    前言 作业发布 组长 成员 贡献分 ★ 530 雨勤 14 311 旭 15 403 俊 16 223 元 14 437 海辉 17 7天 Beta 冲刺站立会议博客链接汇总 Beta 冲刺 (1/7 ...

  5. 基于SSH实现员工管理系统之框架整合篇

    本篇文章来源于:https://blog.csdn.net/zhang_ling_yun/article/details/77803178 以下内容来自慕课网的课程:基于SSH实现员工管理系统之框架整 ...

  6. 业务-----部门Service常用逻辑

    1.org实体类 public class Org implements Serializable { private static final long serialVersionUID = 1L; ...

  7. JavaScript使用childNodes和children

    childNodes用来获取一个元素的所有子元素,这个包括元素节点和文本节点. children用来获取一个元素的子元素节点,注意只是元素节点 其中DOM中常见的三种节点分别如下: 元素节点:< ...

  8. JQuery基础-- Ajax

    基本格式: get: $.get("url",data,function(res){   #.....   }) post: $.post("url",data ...

  9. Kitematic when login show Error:Tunning socket could not be established

    https://cn.bing.com/search?q=tunning+socket+could+not+be+established&qs=n&form=QBRE&sp=- ...

  10. windows下 navicat_premium破解方法

    https://blog.csdn.net/qq_21205435/article/details/78902052