線段樹 合集

線段樹能夠分爲四個部分 :單點更新 ,成段更新 ,區間合併 ,掃描線。php

 

 單點更新:即只更新葉子節點,能夠單點用PushUP(int rt )來更新。ios

題目: ide

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 區間最值post

#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\n",query(1,1,n,a,b));
            else  update(1,1,n,a,b);            
        }   
    }
    return 0;
}
View Code

 

成段更新:ui

用延遲標記 ,使得更新延遲到下次須要更新or詢問的時候。spa

題目 :code

hdu 1698 Just a Hook update成段替換 query一次總區間 能夠直接輸出 結點的信息。  blog

#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.\n", 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\n",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  線段樹區間更新+離散化

 

 區間合併 :

詢問知足條件的最大區間。 pushup對左右子樹合併。

 

其它 :有的題目應用線段樹須要一些排序 而後掃一遍 矩形面積的並 和 周長並。

線段樹與單調棧結合:2019牛客暑期多校訓練營(第四場)sequence

相關文章
相關標籤/搜索