zoukankan      html  css  js  c++  java
  • 线段树 合集

    线段树可以分为四个部分 :单点更新 ,成段更新 ,区间合并 ,扫描线。

     单点更新:即只更新叶子节点,可以单点用PushUP(int rt )来更新。

    题目: 

    hdu1166 敌兵布阵   update 单点增加 query 区间求和

    /*输入
    t样例
    N(N<=50000) 
    第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
    
    接下来每行有一条命令,命令有4种形式:
    (1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
    (2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
    (3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
    (4)End 表示结束,这条命令在每组数据最后出现;
    10    
    2 3 4 5 6 7 8 9 10
    Query 1 3
    Add 3 6
    Query 2 7
    Sub 10 2
    Add 6 3
    Query 3 10
    End 
    
    输出
    Case 1:
    33
    */
    
    #include <iostream>
    #include <string>
    using namespace std; 
    //线段树模板(单点更新)
    #define Mid ((l+r)>>1)  // l+r/2;
    #define lson rt<<1,l,Mid //2*rt,l,mid,
    #define rson rt<<1|1,Mid+1,r  //2*rt+1 ,mid+1,r;
    const int maxn = 100010;
    int sum[maxn<<2];
     
    void build(int rt,int l,int r)
    {
        if(l==r)
        {
            scanf("%d",&sum[rt]);
        }
        else
        {
            build(lson);
            build(rson);
            sum[rt] = sum[rt<<1] + sum[rt<<1|1];
        }
    }
     
    void update(int rt,int l,int r,int pos,int num,string c)        //修改pos位  值为num
    {
        if(l == r && r == pos){ 
            if(c == "Add")    sum[rt] += num;
            if(c == "Sub")    sum[rt] -= num;
        }
        else{
            if( pos <= Mid)
                update(lson,pos,num,c);
            else        
                update(rson,pos,num,c);                             
            sum[rt] = sum[rt<<1] + sum[rt<<1|1];
        }
    }
     
    int query(int rt,int l,int r,int L,int R)            //查询[L,R]
    {
        if(L <= l && r <= R){
            return sum[rt];
        }
        else{
            int tmp = 0;
            if( L <= Mid)
                tmp += query(lson,L,R);
            if( R > Mid)
                tmp += query(rson,L,R);
            return tmp;
        }
    }
    
    int main()
    {
        int  t,n,g=0,a,b;
        string c;
        cin>>t;
        while(t--)
        {
            g+=1;//case:g
            cin>>n;
    
             build(1,1,n);
             cout<<"Case "<<g<<":"<<endl;
             while(cin>>c)
             {
                 if(c=="End") break;
                 cin>>a>>b;
                 if(c=="Sub") update(1,1,n,a,b, "Sub");
                
                if(c=="Add") update(1,1,n,a,b, "Add");
                
                if(c=="Query") cout<<query(1,1,n,a,b)<<endl;            
            }
            
        }
    }
    View Code

    hdu1754 I Hate It  update 单点替换 query 区间最值

    #include <iostream>
    #include <string>
    #include <cstdio> 
    #include <algorithm>
    using namespace std; 
    //线段树模板(单点更新)
    #define Mid ((l+r)>>1)  // l+r/2;
    #define lson rt<<1,l,Mid //2*rt,l,mid,
    #define rson rt<<1|1,Mid+1,r  //2*rt+1 ,mid+1,r;
    const int maxn = 222222;
    int sum[maxn<<2];
    //PushUp函数更新节点信息 ,这里是最值 。 
    void PushUp(int rt){
        sum[rt] = max(sum[rt<<1], sum[ rt<<1|1]);  
    }
    
    void build(int rt,int l,int r)
    {
        if(l==r)
        {
            scanf("%d",&sum[rt]);
            return ; 
        }
        else
        {
            build(lson);
            build(rson);
            PushUp(rt);
        }
    }
     
    void update(int rt,int l,int r,int pos,int num) //修改pos位  值为num
    {
        if(l == r && r == pos){ 
               sum[rt] = num;
        }
        else{
            if( pos <= Mid) update(lson,pos,num);
            else   update(rson,pos,num);                             
            PushUp(rt);
        }
    }
     
    int query(int rt,int l,int r,int L,int R)            //查询[L,R]
    {
        if(L <= l && r <= R)
        {
            return sum[rt];
        }
        int ret =0;
        if( L <= Mid)      ret= max(ret,query(lson,L,R));
        if( R > Mid)          ret= max(ret,query(rson,L,R));
        return ret;
    }
    
    int main()
    {
        int n,m;
        
        while(~(scanf("%d%d",&n,&m)))
        {
             build(1,1,n);
             while(m--)
             {
                 char c;
                 int a,b;
                scanf(" %c%d%d",&c,&a,&b);
                if(c=='Q') printf("%d
    ",query(1,1,n,a,b));
                else  update(1,1,n,a,b);            
            }   
        }
        return 0;
    }
    View Code

    成段更新:

    用延迟标记 ,使得更新延迟到下次需要更新or询问的时候。

    题目 :

    hdu 1698 Just a Hook update成段替换 query一次总区间 可以直接输出 结点的信息。  

    #include <cstdio>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define Mid ((l+r)>>1)
    #define lson rt<<1,l,Mid
    #define rson rt<<1|1,Mid+1,r
    const int maxn = 100010;
    int sum[maxn<<2],add[maxn<<2];
     
    void build(int rt,int l,int r)
    {
        add[rt] = 0;
        if(l == r){
           sum[rt]=1;                  
        }else{
            build(lson);
            build(rson);
            sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        }
    }
     
    void pushDown(int rt,int len)
    {
        add[rt<<1] = add[rt<<1|1] = add[rt];
        sum[rt<<1] = (len-(len>>1))*add[rt];
        sum[rt<<1|1] = (len>>1)*add[rt];
        add[rt] = 0;
    }
     
    void update(int rt,int l,int r,int L,int R,int z)    //更新[L,R]为z
    {
        if(L <= l && r <= R){
            add[rt] = z;
            sum[rt] = (r-l+1)*z;
        }else{
            if(add[rt])
                pushDown(rt,r-l+1);
            if(L <= Mid)
                update(lson,L,R,z);
            if(R > Mid)
                update(rson,L,R,z);
            sum[rt] = sum[rt<<1] + sum[rt<<1|1];
        }
    }
     
    int main()
    {
        int t,cnt=1;
        scanf("%d",&t);
        while(t--)
        {
            int n,q;
            scanf("%d%d",&n,&q);
            build(1,1,n);
            while(q--)
            {
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                update(1,1,n,x,y,z);
            }
            printf("Case %d: The total value of the hook is %d.
    ", cnt++,sum[1]);
        }
        return 0;
    }
    View Code

    poj 3468  A Simple Problem with Integers  update 成段增减 query 区间求和。(待完善)

    #include <stdio.h>
    #define Mid ((l+r)>>1)
    #define lson rt<<1,l,Mid
    #define rson rt<<1|1,Mid+1,r
    const int maxn = 100010;
    int sum[maxn<<2],add[maxn<<2];
     
    void build(int rt,int l,int r)
    {
        add[rt] = 0;
        if(l == r){
           scanf("%d",&sum[rt]);                
        }else{
            build(lson);
            build(rson);
            sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        }
    }
     
    void pushDown(int rt,int len)
    {
        add[rt<<1] += add[rt<<1|1] = add[rt];
        sum[rt<<1] += (len-(len>>1))*add[rt];
        sum[rt<<1|1]+= (len>>1)*add[rt];
        add[rt] = 0;
    }
     
    void update(int rt,int l,int r,int L,int R,int z)    //更新[L,R]增加z 
    {
        if(L <= l && r <= R){
             add[rt] += z;
            sum[rt] +=(r-l+1)*z; 
        }else{
            if(add[rt])
                pushDown(rt,r-l+1);
            if(L <= Mid)
                update(lson,L,R,z);
            if(R > Mid)
                update(rson,L,R,z);
            sum[rt] = sum[rt<<1] + sum[rt<<1|1];
        }
    }
     
    int query(int rt,int l,int r,int L,int R)           //查询[L,R],调用:(1,1,n,L,R)
    {
        if(L <= l && r <= R){
            return sum[rt];
        }
        else
        {
            if(add[rt])
                pushDown(rt,r-l+1);
            int t = 0;
            if(L <= Mid)
                t += query(lson,L,R);
            if(R > Mid)
                t += query(rson,L,R);
            return t;
        }
    }
    
    int  main()
    {
        int n,q;
        while(~scanf("%d%d",&n,&q))
        {
            build(1,1,n);
            while(q--)
            {
                char s;
                int a,b,c;
                scanf("%c",&s);
                if(s=='Q') 
                {
                    scanf("%d%d",&a,&b);
                    int ans=query(1,1,n,a,b);
                    printf("%d
    ",ans);
                } 
                else if(s=='C')
                {
                    scanf("%d%d%d",&a,&b,&c);
                    update(1,1,n,a,b,c);
                }
            }
        }    
        return 0;
    }
    View Code

    poj 2528 Mayor's posters  线段树区间更新+离散化(待更新)

    /*
    639.线段树-贴海报 (10分)
    C时间限制:3000 毫秒 |  C内存限制:3000 Kb
    题目内容:
    由10^7块1x1的玻璃构成1x10^7的海报墙,每个海报完整地覆盖几块玻璃,海报的宽度可以不同。后来的人可以覆盖
    前人的海报。一张海报如果有没被覆盖的部分,则称为可视海报。你的任务是找出有多少可视海报。
    输入描述
    第一行是测试的总数c,接下来的行是各测试用例。
    每个测试的第一行是海报的总数n, n<=10000, 然后是n个按先后顺序贴的海报的位置li, ri. 满足1<=li<=ri<=10^7。
    
    
    输出描述
    每个测试的可视海报数目
    
    输入样例
    1
    5
    1 4
    2 6
    8 10
    3 4
    7 10
    
    输出样例
    4
    */ 
    
    #include <iostream>  
    #include <stdio.h>  
    #include <string.h>  
    #include <algorithm>  
    using namespace std;  
    #define N 11111  
    #define lson l, m, rt<<1  
    #define rson m+1, r, rt<<1|1  
    #define abbreviations int l,int r,int rt  
    #define mid (l+r)>>1  
    int le[N],ri[N],root[N<<4],lr[N<<4],m,cnt;  
    bool flag[N<<4];  
      
    void update(abbreviations, int L,int R,int c)  
    {  
          if(L <= l && R >= r)  
          {  
                root[rt] = c;  
                return ;  
          }  
          if(root[rt] != -1)  
          {  
              root[rt<<1] = root[rt<<1|1] = root[rt];  
              root[rt] = -1;  
          }  
          int m = mid;  
          if(m >= L) update(lson,L,R,c);  
          if(m < R) update(rson,L,R,c);  
      
    }  
    void query(abbreviations)  
    {  
      
         if(root[rt] != -1)  
         {  
               if(!flag[root[rt]]) cnt++;  
                    flag[root[rt]] = true;  
               return ;  
         }  
         if(l == r)  
          return ;  
         int m = mid;  
         query(lson);  
         query(rson);  
    }  
    int main()  
    {  
        int t,n,i,nn;  
        scanf("%d",&t);  
        while(t--)  
        {  
              scanf("%d",&n);  
              for(i = 0,nn = 0; i < n; i++)  
              {  
                    scanf("%d%d",&le[i],&ri[i]);  
                    lr[nn++] = le[i];  //记录左端点  
                    lr[nn++] = ri[i];  //记录右端点  
              }  
              sort(lr,lr+nn);  //排序不能少  
              m = unique(lr,lr+nn)-lr;  //去重  
      
              for(i = m-1; i >= 0; i--)  
              {  
                    if(lr[i] != (lr[i-1]+1)) lr[m++] = lr[i] + 1;  //相邻数字大于1就添加一个数  
              }  
              sort(lr,lr+m);  //添加数字后不要忘记排序  
              memset(root,-1,sizeof(root));  //建树叶子节点全部赋值为-1  
      
              for(i = 0; i < n; i++)  
              {  
                    int L = lower_bound(lr, lr+m, le[i]) - lr; //二分查找左端点  
                    int R = lower_bound(lr, lr+m, ri[i]) - lr; //二分查找右端点  
                    update(0, m, 1, L, R, i);  //更新  
              }  
              memset(flag,false,sizeof(flag));  
              cnt = 0;  
              query(0, m, 1);  //求出答案  
              printf("%d
    ",cnt);  
        }  
        return 0;  
    }
    View Code

     区间合并 :

    询问满足条件的最大区间。 pushup对左右子树合并。

    其它 :有的题目应用线段树需要一些排序 然后扫一遍 矩形面积的并 和 周长并。

    线段树与单调栈结合:2019牛客暑期多校训练营(第四场)sequence

  • 相关阅读:
    JAVA网络编程-IP组播
    Centos7安装Node
    Android Studio解决support-annotations版本冲突
    Wordpresss建站笔记:英文模板出现中文如何解决?
    Win10系统下插入耳机前面板无声后面板有声的处理(二)
    webstorm编辑器html浏览器快捷浏览按键图标消失的处理
    近期的感想
    Octet string 解析
    SSH隧道:端口转发功能详解
    uint, not []uint8
  • 原文地址:https://www.cnblogs.com/young-children/p/11743879.html
Copyright © 2011-2022 走看看