線段樹(單點更新與區域更新)
線段樹
實在不好意思不寫了哈哈哈啊哈。
線段樹主要是解決一些大量操作區間並且維護區間的題目(維護的區間要有加和性)。
線段樹核心函式有以下幾個
- pushup()(主要用來向上跟新節點資訊)
- pushdown()(用來向下更新來不及更新的節點)
- query()(查詢當前區間的維護值)
- 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-Snacks(DFS序+線段樹,單點修改,區間查詢)
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5692 Problem Description 百度科技園內有n 個零食機,零食機之間通過n−1 條路相互連通。每個零食機都有一個值v ,表示為小度熊提供零食的價值。 由於零
hdu1394Minimum Inversion Number解題報告---線段樹(單點插值 & 區間逆序數求和)
Minimum Inversion Number Time Limit: 2000
模板 - 數據結構 - 線段樹(單點修改)
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