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

  • 相关阅读:
    request.getParameter() 、 request.getInputStream()和request.getReader() 使用体会
    HTTP之Content-Length
    关于spring3中No Session found for current thread!and Transaction的配置和管理(转)
    Java数据类型和MySql数据类型对应一览
    Spring MVC 解读——View,ViewResolver(转)
    LeetCode 441. Arranging Coins
    LeetCode 415. Add Strings
    LeetCode 400. Nth Digit
    LeetCode 367. Valid Perfect Square
    LeetCode 326. Power of Three
  • 原文地址:https://www.cnblogs.com/young-children/p/11743879.html
Copyright © 2011-2022 走看看