·专题」 线段树

初学线段树(SegmentTree)

从HH大神那你学来的模板风格。

感觉确实相当飘逸。

现在做了4题。。单点更新的,

想放上来,,以后慢慢整理!!

·单点更新」      ·刷题参考」

  • hdu1166 敌兵布阵
    • 线段树第一题,单点更新第一题,可以作为线段树的模板,

    • 思路:兵工厂作为数量n映射作为线段总长,更具输入进行单点的更新与查询,sub操作可以理解为add一个负数 

    • Query操作:区间求和
      update操作:单点的增减

    •  1 #include<cstdio>
      2
      3 #define lson l, m, rt<<1
      4 #define rson m + 1, r, rt<<1 | 1
      5 #define mid(a,b) (a+b)>>1
      6 #define maxn 55555
      7
      8 int sum[maxn<<2];
      9
      10 void PushUP(int rt)
      11 {
      12 sum[rt] = sum[rt<<1] + sum[rt<<1|1];
      13 }
      14
      15 void Build(int l,int r,int rt)
      16 {
      17 if(l == r)
      18 {
      19 scanf("%d",&sum[rt]);
      20 return;
      21 }
      22 int m = mid(l,r);
      23 Build(lson);
      24 Build(rson);
      25 PushUP(rt);
      26 }
      27
      28 void Update(int p,int add,int l,int r,int rt)
      29 {
      30 if(l == r)
      31 {
      32 sum[rt] += add;
      33 return;
      34 }
      35 int m = mid(l,r);
      36 if(p <= m)
      37 Update(p,add,lson);
      38 else
      39 Update(p,add,rson);
      40
      41 PushUP(rt);
      42 }
      43
      44 int Query(int L,int R,int l,int r,int rt)
      45 {
      46 if(L <= l && r<= R)
      47 {
      48 return sum[rt];
      49 }
      50 int m = mid(l,r);
      51 int ans = 0;
      52 if(L <= m)
      53 ans += Query(L,R,lson);
      54 if(R > m)
      55 ans += Query(L,R,rson);
      56
      57 return ans;
      58 }
      59
      60
      61 int main()
      62 {
      63 int T,n,a,b;
      64 scanf("%d",&T);
      65 for(int cas=1;cas<=T;cas++)
      66 {
      67 printf("Case %d:\n",cas);
      68 scanf("%d",&n);
      69 Build(1,n,1);
      70
      71 char op[10];
      72
      73 while(scanf("%s",op) && op[0] != ‘E‘)
      74 {
      75 scanf("%d %d",&a,&b);
      76 if(op[0] == ‘Q‘)
      77 printf("%d\n",Query(a,b,1,n,1));
      78 else if(op[0] == ‘S‘)
      79 Update(a,-b,1,n,1);
      80 else
      81 Update(a,b,1,n,1);
      82 }
      83 }
      84 return 0;
      85 }


  • hdu1754 I Hate It
    • Query操作:区间最值
      update操作:单点替换

    •  1 #include<cstdio>
      2 #include<algorithm>
      3 using namespace std;
      4 #define lson l, m, rt<<1
      5 #define rson m + 1, r, rt<<1 | 1
      6 #define mid(l,r) (l+r)>>1
      7 #define maxn 222222
      8
      9 int MAX[maxn<<2];
      10
      11 void PushUP(int rt)
      12 {
      13 MAX[rt] = max(MAX[rt<<1],MAX[rt<<1|1]);
      14 }
      15
      16 void Build(int l,int r,int rt)
      17 {
      18 if(l == r)
      19 {
      20 scanf("%d",&MAX[rt]);
      21 return;
      22 }
      23 int m = mid(l,r);
      24 Build(lson);
      25 Build(rson);
      26 PushUP(rt);
      27 }
      28
      29 void Update(int p,int sc,int l,int r,int rt)
      30 {
      31 if(l == r)
      32 {
      33 MAX[rt] = sc;
      34 return;
      35 }
      36 int m = mid(l,r);
      37 if(p <= m)
      38 Update(p,sc,lson);
      39 else
      40 Update(p,sc,rson);
      41 PushUP(rt);
      42 }
      43
      44 int Query(int L,int R,int l,int r,int rt)
      45 {
      46 if(L <= l && r <= R)
      47 return MAX[rt];
      48 int m = mid(l,r);
      49 int ans = 0;
      50 if(L <= m)
      51 ans = max(ans,Query(L,R,lson));
      52 if(R > m)
      53 ans = max(ans,Query(L,R,rson));
      54
      55 return ans;
      56 }
      57
      58
      59
      60 int main()
      61 {
      62 int n,m,a,b;
      63 while(~scanf("%d%d",&n,&m))
      64 {
      65 Build(1,n,1);
      66 while(m--)
      67 {
      68 char op[2];
      69 scanf("%s%d%d",op,&a,&b);
      70 if(op[0] == ‘Q‘)
      71 printf("%d\n",Query(a,b,1,n,1));
      72 else
      73 Update(a,b,1,n,1);
      74 }
      75 }
      76 return 0;
      77 }


  • hdu1394
    Minimum Inversion Number
     

  • 这里学习到了逆序数的求法,归并排序求,线段树,树状数组,点树
    • 求逆序数的方法   
       

    • 1394方法总结

    • 思路:每插入一个数,就进行一次询问并更新(询问当前线段树中比X小的数的个数,询问区间为[x,n-1])

    •  
      注:因为插入的数不会有重复且为0到N-1,所以询问时应该是在区间[x,n-1]

    •  关于逆序数递推:求出原序列的逆序数后,通过递推确定最小的逆序数 

    •  
      这里把一个数x移到末尾,比x小的数[0...x-1]共x个都在x的前面了 ,逆序数减少x

    •  
         
       比x大的树[x+1...N-1]共n-1-x个都在x的前面了,逆序数增加n-1-x个

    •  
          最后的逆序数变化为  res = res + n-1-x - x = res +
      n-1-2*x

    • Query操作:区间求和
      update操作:单调增减

    •  1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 using namespace std;
      5 #define maxn 5555
      6 #define CLR(a,b) memset(a,b,sizeof(a))
      7 #define lson l, m, rt << 1
      8 #define mid(l,r) (l+r)>>1
      9 #define rson m+1, r, rt << 1 | 1
      10
      11
      12 int sum[maxn<<2];
      13 int x[maxn],n;
      14
      15 void PushUP(int rt)
      16 {
      17 sum[rt] = sum[rt<<1] + sum[rt<<1|1];
      18 }
      19
      20
      21 void Update(int p,int l,int r,int rt)
      22 {
      23 if(l == r)
      24 {
      25 sum[rt]++;
      26 return;
      27 }
      28 int m = mid(l,r);
      29 if(p <= m)
      30 Update(p,lson);
      31 else
      32 Update(p,rson);
      33 PushUP(rt);
      34 }
      35
      36 int Query(int L,int R,int l,int r,int rt)
      37 {
      38 if(L <= l && r <= R)
      39 return sum[rt];
      40 int m = mid(l,r);
      41 int ans = 0;
      42 if(L <= m)
      43 ans += Query(L,R,lson);
      44 if(R > m)
      45 ans += Query(L,R,rson);
      46 return ans;
      47 }
      48
      49
      50 int main()
      51 {
      52 while(~scanf("%d",&n))
      53 {
      54 CLR(sum,0);
      55 int res = 0;
      56 for(int i=0;i<n;i++)
      57 {
      58 scanf("%d",&x[i]);
      59 res += Query(x[i],n-1,0,n-1,1);
      60 Update(x[i],0,n-1,1);
      61 }
      62 int ret = res;
      63 for(int i=0;i<n;i++)
      64 {
      65 res += n - 1 - x[i] - x[i];
      66 ret = min(ret,res);
      67 }
      68 printf("%d\n",ret);
      69 }
      70
      71 return 0;
      72 }


  • hdu2795 Billboard
    • 思路:
      将h这一维映射到线段树的区间,w这一维对应区间点上的最大值,

    •  
      每次询问的时候(询问先左后右),做一次插入的操作,相应的h维度的值减少wi

    •  
      参考blog

    • Query操作:
      返回区间最大值的位置(hh大神直接把update写里面了)

    •  1 #include<cstdio>
      2 #include<algorithm>
      3 using namespace std;
      4
      5 #define lson l, m, rt << 1
      6 #define rson m+1, r, rt << 1 | 1
      7 #define mid(l,r) (l+r) >> 1
      8 #define maxn 222222
      9
      10 int MAX[maxn<<2];
      11 int h,w,n;
      12
      13 void PushUP(int rt)
      14 {
      15 MAX[rt] = max(MAX[rt<<1], MAX[rt<<1|1]);
      16 }
      17
      18 void Build(int l,int r,int rt)
      19 {
      20 MAX[rt] = w;
      21 if(l == r)
      22 return;
      23 int m = mid(l,r);
      24 Build(lson);
      25 Build(rson);
      26 }
      27
      28 int Query(int x,int l,int r,int rt)
      29 {
      30 if(l == r) //找到可以放置的位置
      31 {
      32 MAX[rt] -= x;
      33 return l;
      34 }
      35 int m = mid(l,r);
      36 int ret = (MAX[rt<<1] >= x) ? Query(x,lson) : Query(x,rson);
      37 PushUP(rt);
      38 return ret;
      39 }
      40
      41 int main()
      42 {
      43 while(~scanf("%d%d%d",&h,&w,&n))
      44 {
      45 h = min(h,n);
      46 Build(1,h,1);
      47 while(n--)
      48 {
      49 int x;
      50 scanf("%d",&x);
      51 if(MAX[1] < x) puts("-1");
      52 else printf("%d\n",Query(x,1,h,1));
      53 }
      54 }
      55 return 0;
      56 }

·专题」 线段树

时间: 2025-01-10 02:55:36

·专题」 线段树的相关文章

&#183;专题」 线段树

PKU暑期培训第一天,这次培训人很多,但是感觉打酱油的也不少,不知道大牛有多少. 第一天都是讲线段树的,课件的话和往常一样,没什么变化. 具体的话,讲了线段树和树状数组.线段树的话讲了单点更新,成段更新,扫描线已经离散化. 然后随便提了提树状数组.估计明天再讲一点点,然后接着是讲并查集,多串匹配什么的. 线段树的题目我做得很少,以前看过HH大神的模板,想模仿来着,其实也没什么理解. 重新理解一下线段树吧. 线段树的用途,主要是维护区间问题,比如区间的单点更新操作,成段更新,扫描线等等.当然还有一

「模板」 线段树——区间乘 &amp;&amp; 区间加 &amp;&amp; 区间求和

「模板」 线段树--区间乘 && 区间加 && 区间求和 <题目链接> 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long long p; class SegmentTree { private: struct Node { int l,r; long long v,mul,add; Node *c[2]; Node(int l,int r):l(l),r(r),mul(1LL),add(0LL) { c[

【算法系列学习】线段树vs树状数组 单点修改,区间查询 [kuangbin带你飞]专题七 线段树 A - 敌兵布阵

https://vjudge.net/contest/66989#problem/A 单点修改,区间查询 方法一:线段树 http://www.cnblogs.com/kuangbin/archive/2011/08/15/2139834.html 1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<cmath> 6 #

「模板」线段树静态开点(单点+区间修改)、动态开点

相关讲解资料: 树状数组:https://blog.csdn.net/qq_34374664/article/details/52787481 (线段树预备) 线段树讲解: 初学版:https://blog.csdn.net/zearot/article/details/52280189 进阶完整版:https://www.cnblogs.com/AC-King/p/7789013.html 代码: 完整注释模板一张,参(chao)考(xi)楼上的博客 #include<iostream> #

[kuangbin带你飞]专题七 线段树

A - 敌兵布阵 HDU - 1166 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视. 中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少

「ZJOI2019」线段树

传送门 Description 线段树的核心是懒标记,下面是一个带懒标记的线段树的伪代码,其中 tag 数组为懒标记: 其中函数\(Lson(Node)\)表示\(Node\)的左儿子,\(Rson(Node)\)表示\(Node\)的右儿子. 有一棵 \([1,n]\)上的线段树,编号为\(1\) .初始时什么标记都没有. 每次修改会把当前所有的线段树复制一份,然后对于这些线段树实行一次区间修改操作. 每次修改后线段树棵数翻倍,第 \(i\)次修改后,线段树共有 \(2^i\) 棵. 每次询问

[kuangbin]带你飞之&#39;线段树&#39;专题(未完成)

// 带飞网址 https://vjudge.net/article/187 专题七 线段树 HDU 1166 敌兵布阵HDU 1754 I Hate It√ POJ 3468 A Simple Problem with IntegersPOJ 2528 Mayor's postersHDU 1698 Just a HookZOJ 1610 Count the ColorsPOJ 3264 Balanced LineupHDU 4027 Can you answer these queries?

java,线段树

线段树: 你可以理解成:线段组成的树,很多人问我,线段树到底有何用处,其实这个问题,你可以自己去刷题,然后总结出检验. 线段的具体理解,我看到一篇很好的博客,我就不展开了.博客地址:https://blog.csdn.net/iwts_24/article/details/81484561 基础题目: hdu1166敌兵布阵: 如果我们没有学过线段树,我们肯定是用模拟+暴力的方法. 模拟+暴力的方法代码: package Combat.com; import java.math.BigInteg

线段树--数据结构专题学习

这两周是数据结构专题的学习,,被专题的题目虐得死去活来== 线段树:简单的说就是把[1,n]的区间二分,[1,(1+n)/2]左子树,[(1+n)/2+1,n]右子树 就这样一直分下去,直到都是[x,x]这样的区间.这样就构成了一颗树了^-^ 有这样一棵树,我们就可以在节点中储存区间的和啊,区间内的最大值啊,最小值等等..这就是线段树的附加信息了,也是题目中的重点.. 我们可以用一个数组(长度为k)储存原区间的初始值,然后根据这个建树,所以这个树的节点数最多为4*K: 对于每个节点i,其左子树为