1. 程式人生 > >線段樹(單點更新與區域更新)

線段樹(單點更新與區域更新)

線段樹

實在不好意思不寫了哈哈哈啊哈。
線段樹主要是解決一些大量操作區間並且維護區間的題目(維護的區間要有加和性)。
線段樹核心函式有以下幾個

  1. pushup()(主要用來向上跟新節點資訊)
  2. pushdown()(用來向下更新來不及更新的節點)
  3. query()(查詢當前區間的維護值)
  4. updata()(更新一個區域或者一個點的資訊)
    注意
    單點更新是不需要pushdown函式的,並且維護資訊裡面沒有lazy標記(具體會在區間更新裡面詳細敘述),而且線段樹儘量用scanf和printf更快。
    不多說放題!!!
    hdu 1166 戳這裡
    這是一道典型的區間單點更新問題,只需要找到根節點並且修改值,並且用pushup()傳到樹頂就行。但是值得注意的是線段樹的題目一般操作次數很多,資料有的時候很大,用long long int存比較好,而且線段樹的陣列需要開到區域的4倍大小,不然很容易runtime!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
#include<iomanip> #define MAXN 50000 using namespace std; #define ll long long int struct node{ ll key; ll lazy; }; node p[4*MAXN]; ll num[4*MAXN]; ll q=1,n; void pushup(node p[],ll n) { p[n].key=p[2*n].key+p[2*n+1].key; } void buildtree(node p[],ll n,ll l,ll r) { p[n].lazy=0; if
(l==r) { p[n].key=num[q]; q++; return ; } ll mid=(l+r)/2; buildtree(p,2*n,l,mid); buildtree(p,2*n+1,mid+1,r); pushup(p,n); } void pushdown(node p[],ll n,ll l,ll r) { if(l!=r) { ll mid=(r+l)/2; p[2*n].lazy=p[n].lazy; p[2*n].key=(mid-l+1)*p[2*n].lazy; p[2*n+1].lazy=p[n].lazy; p[2*n+1].key=(r-mid)*p[2*n+1].lazy; } p[n].lazy=0; } void updata(node p[],ll n,ll l,ll r,ll i,ll c) { ll mid=(l+r)/2; if(l==r&&l==i) { p[n].key+=c; return ; } if(i<=mid) updata(p,2*n,l,mid,i,c); else updata(p,2*n+1,mid+1,r,i,c); if(l!=r) pushup(p,n); } ll query(node p[],ll n,ll l,ll r,ll x,ll y) { if(l==x&&r==y) return p[n].key; if(p[n].lazy) pushdown(p,n,l,r); ll mid=(l+r)/2; if(y<=mid) return query(p,2*n,l,mid,x,y); else if(x>mid) return query(p,2*n+1,mid+1,r,x,y); else return query(p,2*n,l,mid,x,mid)+query(p,2*n+1,mid+1,r,mid+1,y); } int main() { ll t; ll w; scanf("%lld",&t); w=t; while(t--) { q=1; ll n; scanf("%lld",&n); for(ll i=1;i<=n;i++) { ll a;scanf("%lld",&a); num[i]=a; } buildtree(p,1,1,n); printf("Case %lld:\n",w-t); string s; while(cin>>s) { if(s=="End") break; if(s=="Query") { ll i,j; scanf("%lld%lld",&i,&j); printf("%lld\n",query(p,1,1,n,i,j)); } if(s=="Sub") { ll i,j; scanf("%lld%lld",&i,&j); updata(p,1,1,n,i,-1*j); } if(s=="Add") { ll i,j; scanf("%lld%lld",&i,&j); updata(p,1,1,n,i,j); } } } }

區間更新

區間跟新的題目比比單點更新稍微多一點東西,比如pushdown函式和lazy標記。
首先 lazy標記有什麼用處?
由於線段樹的大量操作,所以全部更新到樹根未免太浪費時間了,所以我們用lazy標記儲存住這個更新結果,如果我們下次訪問需要更新到這個區間以下,再去用pushdown()更新。
hdu 1698 戳這裡

#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
#include<iomanip>
using namespace std;
#define MAXN 200000
#define ll long long int
struct node{
    ll key;
    ll lazy;
};
node p[4*MAXN];
ll q,n;
void pushup(node p[],ll n)
{
    p[n].key=p[2*n].key+p[2*n+1].key;
}
void buildtree(node p[],ll n,ll l,ll r)
{     p[n].lazy=0;
    if(l==r)
    {
        p[n].key=1;
        return ;
    }
    else
    {    ll mid=(l+r)/2;
        buildtree(p,2*n,l,mid);
        buildtree(p,2*n+1,mid+1,r);     
    }
    pushup(p,n);
    return ;
}
void pushdown(node p[],ll n,ll l,ll r)
{
    if(p[n].lazy)
    {   ll mid=(l+r)/2;
        p[2*n].lazy=p[n].lazy;
        p[2*n].key=p[2*n].lazy*(mid-l+1);
        p[2*n+1].lazy=p[n].lazy;
        p[2*n+1].key=(r-mid)*p[2*n+1].lazy;
    }
    p[n].lazy=0;
}
void updata(node p[],ll n,ll l,ll r,ll x,ll y,ll lazy)
{
    if(l==x&&r==y)
    {   p[n].lazy=lazy;
        p[n].key=(r-l+1)*p[n].lazy;
        return ;
    }
    if(p[n].lazy)
    pushdown(p,n,l,r);
    ll mid=(l+r)/2;
    if(x<=mid)
    updata(p,2*n,l,mid,x,min(y,mid),lazy);
    if(y>mid)
    updata(p,2*n+1,mid+1,r,max(x,mid+1),y,lazy);
    if(l!=r)
    pushup(p,n);

}
int query(node p[],ll n,ll l,ll r,ll x,ll y)
{    
    if(l==x&&r==y)
    {
        return p[n].key;
    }
    ll mid=(l+r)/2;

    if(y<=mid) return query(p,2*n,l,mid,x,y);
    else if(x>mid) return query(p,2*n+1,mid+1,r,x,y);
    else return query(p,2*n,l,mid,x,mid)+query(p,2*n+1,mid+1,r,mid+1,y);
}
int main()
{    int t;
    scanf("%d",&t);
    int w=t;
    while(t--)
    {    
        scanf("%lld%lld",&n,&q);
        buildtree(p,1,1,n); 
        for(ll i=1;i<=q;i++)
        {
            ll x,y,z;
            scanf("%lld%lld%lld",&x,&y,&z);
            updata(p,1,1,n,x,y,z);
        }
        printf("Case %d: The total value of the hook is %lld.\n",w-t,query(p,1,1,n,1,n));
    }
} 

記住好嗎!!!!!!!!

相關推薦

線段修改,區間查詢

/* * 線段樹模板 * 單點修改,區間查詢 */ #include<iostream> #include<cstdio> using namespace std; typedef long long LL; const int M

線段更新區域更新

線段樹 實在不好意思不寫了哈哈哈啊哈。 線段樹主要是解決一些大量操作區間並且維護區間的題目(維護的區間要有加和性)。 線段樹核心函式有以下幾個 pushup()(主要用來向上跟新節點資訊) pushdown()(用來向下更新來不及更新的節點) quer

HDU 1166 敵兵佈陣【線段更新區間求和

C國的死對頭A國這段時間正在進行軍事演習,所以C國間諜頭子Derek和他手下Tidy又開始忙乎了。A國在海岸線沿直線佈置了N個工兵營地,Derek和Tidy的任務就是要監視這些工兵營地的活動情況。由於採取了某種先進的監測手段,所以每個工兵營地的人數C國都掌握的一清二楚,每個工兵營地的人數都有可能發生

zkw張昆瑋線段更新

本題目包含多組測試,請處理到檔案結束。 在每個測試的第一行,有兩個正整數 N 和 M ( 0<N<=200000,0<M<5000 ),分別代表學生的數目和操作的數目。 學生ID編號分別從1編到N。 第二行包含N個整數,代表這N個學生的初始成績,其中第i個數代表ID為i的學生的成績。

HDU-5692-SnacksDFS序+線段修改,區間查詢

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5692 Problem Description 百度科技園內有n 個零食機,零食機之間通過n−1 條路相互連通。每個零食機都有一個值v ,表示為小度熊提供零食的價值。 由於零

hdu1394Minimum Inversion Number解題報告---線段插值 & 區間逆序數求和

                              Minimum Inversion Number Time Limit: 2000

hdu1754I Hate It解題報告---線段替換 & 區間最值

                                        I Hate I

模板 - 數據結構 - 線段修改

amp ret oid update pan 單點 返回 code == 這裏是以區間最大值為例,要修改成其他的運算,註意修改每個函數的運算以及query中返回的無關值。 這裏的區間最大值設置的最小元素為-1(在query中表示與當前區間不相交的區間的結果)。 註意因為調用

線段修改,區間求和,區間最大

(一)線段樹 1.E - Lost Cows   N (2 <= N <= 8,000) cows have unique brands in the range 1..N. In a spectacular display of poor judgment, they visited

hdu 1166敵兵佈陣線段 模板 更新加區間查詢

#include<iostream> #include<cstdio> #include<cstring> #include<cstring> #include<algorithm> using namespac

線段模板-更新 區間求和nefuoj1472

#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; #define maxn 10000

線段dfs序建樹加區間更新查詢

記錄一下這道折磨了我一天的題,。。。。 具體思路: 具體關係可通過dfs序建樹,但是注意,在更新以及查詢時的數和你dfs序建成的數是不一樣的。因為你dfs序建成的樹每個左右區間以及端點會發生不符合建樹的條件。但是具體區間的更新還是可以通過新的樹進行更新的,但是下屬關係還

線段模板(更新

div ret onclick 更新 turn space view date span 1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #inc

A - 敵兵布陣 HDU - 1166 線段修改當修改

scan () 線段 int uil 多點 upd ase include 線段樹板子題練手用 1 #include<cstdio> 2 using namespace std; 3 const int maxn=5e4+8; 4 int a[maxn

codeforces 438D The Child and Sequence(線段更新+區間取模+區間和)

題意: 一個n個數的序列。對它進行 3 種操作。 1 l r:輸入a[l,r]的和 2 l r x:令[l,r]所有數對x取模 3 k x:令a[k] = x 每到操作1時輸出和。 (1 ≤ n, m ≤ 1e5). (1 ≤ a[i] ≤ 

POJ 2828Buy Tickets(線段維護)

-a plm hat output lang little select color schedule Buy Tickets Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 2046

zkw線段-Build(),Updata(),Query()。

#include<bits/stdc++.h> using namespace std; #define maxn 100007 int A[maxn];//原陣列,n為原陣列元素個數 ,N為擴充元素個數  int Tree[maxn << 2];//區間和&nbs

【資料結構】【線段修改區間查詢

#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; const int MAXS

線段修改加區間修改

const int maxn=1e6+5; int a[maxn]; //存每個數的值 struct node { int sum; int ll,rr; }tree[maxn*4

深入學習理解二叉搜尋附詳細講解例項分析

寫在前面        本文主要分為三個部分。        第一部分介紹了二叉搜尋樹的基本性質。        第二部分全面詳細地講述了二叉搜尋樹的各種基本操作。包括WALK/遍歷、SEARCH/查詢、MINIMUM/最小關鍵字、MAXIMUM/最大關鍵字、SUCCES