线段树

参考博客:线段树详解

 线段树入门&lazy思想

板子:

//线段树模板(单点更新)
#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];
 
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)        //修改pos位值为num
{
    if(l == r && r == pos){     
        sum[rt] += num;
    }else{
        if( pos <= Mid)
            update(lson,pos,num);
        else        
            update(rson,pos,num);
        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;
    }
}

 

//线段树模板(区间更新)
#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;
    }
}

 

    
    //建树 
    Build(1,n,1); 
    //点修改
    Update(L,C,1,n,1);
    //区间修改 
    Update(L,R,C,1,n,1);
    //区间查询 
    int ANS=Query(L,R,1,n,1);

 

模板题:

敌兵布阵 单点增减,区间求和。

通过代码:

/*输入
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 表示结束,这条命令在每组数据最后出现;

1
10    
1 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:
6
33
59
*/

#include 
#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 "<":"<<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<1,1,n,a,b)<<endl;            
        }
        
    }
}
View Code

算法作业的题目:

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


你可能感兴趣的:(线段树)