1、線段樹html
http://www.cnblogs.com/TheRoadToTheGold/p/6254255.htmlnode
一、建樹,即創建一棵線段樹ios
主體思路:a、對於二分到的每個結點,給它的左右端點肯定範圍。ide
b、若是是葉子節點,存儲要維護的信息。ui
c、狀態合併。spa
void build(int k,int l,int r)//建樹 { tree[k].l=l,tree[k].r=r; if(tree[k].l==tree[k].r) { tree[k].w=read(); return ; } int m=(l+r)>>1; build(k<<1,l,m); build(k<<1|1,m+1,r); tree[k].w=tree[k<<1].w+tree[k<<1|1].w; }
二、單點查詢,即查詢一個點的狀態,設待查詢點爲xcode
主體思路:與二分查詢法基本一致,若是當前枚舉的點左右端點相等,即葉子節點,就是目標節點。若是不是,由於這是二分法,因此設查詢位置爲x,當前結點區間範圍爲了l,r,中點爲 mid,則若是x<=mid,則遞歸它的左孩子,不然遞歸它的右孩子htm
void ask(int k) { if(tree[k].l==tree[k].r) //當前結點的左右端點相等,是葉子節點,是最終答案 { ans=tree[k].w; return ; } int m=(tree[k].l+tree[k].r)/2; if(x<=m) ask(k*2);//目標位置比中點靠左,就遞歸左孩子 else ask(k*2+1);//反之,遞歸右孩子 }
三、單點修改,即更改某一個點的狀態。用引例中的例子,對第x個數加上yblog
主體思路 結合單點查詢的原理,找到x的位置;根據建樹狀態合併的原理,修改每一個結點的狀態。遞歸
void change_point(int k)//單點修改 { if(tree[k].l==tree[k].r) { tree[k].w+=y; return ; } if(tree[k].f) down(k); int m=(tree[k].l+tree[k].r)>>1; if(x<=m) change_point(k<<1); else change_point(k<<1|1); tree[k].w=tree[k<<1].w+tree[k<<1|1].w; }
4.區間修改+區間查詢
void change_interval(int k)//區間修改 { if(tree[k].l>=a&&tree[k].r<=b) { tree[k].w+=y*(tree[k].r-tree[k].l+1); tree[k].f+=y; return ; } if(tree[k].f) down(k); int m=(tree[k].l+tree[k].r)>>1; if(a<=m) change_interval(k<<1); if(b>m) change_interval(k<<1|1); tree[k].w=tree[k<<1].w+tree[k<<1|1].w; } void ask_interval(int k)//區間查詢 { if(tree[k].l>=a&&tree[k].r<=b) { ans+=tree[k].w; return ; } if(tree[k].f) down(k); int m=(tree[k].l+tree[k].r)>>1; if(a<=m) ask_interval(k<<1); if(b>m) ask_interval(k<<1|1); }
5.標記下傳
實現思路
a.原結構體中增長新的變量,存儲這個懶標記。
b.遞歸到這個節點時,只更新這個節點的狀態,並把當前的更改值累積到標記中。注意是累積,能夠這樣理解:過年,不少個親戚都給你壓歲錢,但你暫時不用,因此都被你父母扣下了。
c.何時纔用到這個懶標記?當須要遞歸這個節點的子節點時,標記下傳給子節點。這裏沒必要管用哪一個子節點,兩個都傳下去。就像你若是還有妹妹,父母給大家零花錢時總不能偏愛吧
d.下傳操做:
3部分:①當前節點的懶標記累積到子節點的懶標記中。
②修改子節點狀態。在引例中,就是原狀態+子節點區間點的個數*父節點傳下來的懶標記。
void down(int k)//標記下傳 { tree[k<<1].f+=tree[k].f; tree[k<<1|1].f+=tree[k].f; tree[k<<1].w+=tree[k].f*(tree[k<<1].r-tree[k<<1].l+1); tree[k<<1|1].w+=tree[k].f*(tree[k<<1|1].r-tree[k<<1|1].l+1); tree[k].f=0; }
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 4000001 using namespace std; long long ans; int n,m,q,x,y,a,b; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } struct Tree { int l,r,f;long long w; }tree[N]; void build(int k,int l,int r)//建樹 { tree[k].l=l,tree[k].r=r; if(tree[k].l==tree[k].r) { tree[k].w=read(); return ; } int m=(l+r)>>1; build(k<<1,l,m); build(k<<1|1,m+1,r); tree[k].w=tree[k<<1].w+tree[k<<1|1].w; } void down(int k)//標記下傳 { tree[k<<1].f+=tree[k].f; tree[k<<1|1].f+=tree[k].f; tree[k<<1].w+=tree[k].f*(tree[k<<1].r-tree[k<<1].l+1); tree[k<<1|1].w+=tree[k].f*(tree[k<<1|1].r-tree[k<<1|1].l+1); tree[k].f=0; } void change_point(int k)//單點修改 { if(tree[k].l==tree[k].r) { tree[k].w+=y; return ; } if(tree[k].f) down(k); int m=(tree[k].l+tree[k].r)>>1; if(x<=m) change_point(k<<1); else change_point(k<<1|1); tree[k].w=tree[k<<1].w+tree[k<<1|1].w; } void ask_point(int k)//單點查詢 { if(tree[k].l==tree[k].r) { ans=tree[k].w; return ; } if(tree[k].f) down(k); int m=(tree[k].l+tree[k].r)>>1; if(x<=m) ask_point(k<<1); else ask_point(k<<1|1); } void change_interval(int k)//區間修改 { if(tree[k].l>=a&&tree[k].r<=b) { tree[k].w+=y*(tree[k].r-tree[k].l+1); tree[k].f+=y; return ; } if(tree[k].f) down(k); int m=(tree[k].l+tree[k].r)>>1; if(a<=m) change_interval(k<<1); if(b>m) change_interval(k<<1|1); tree[k].w=tree[k<<1].w+tree[k<<1|1].w; } void ask_interval(int k)//區間查詢 { if(tree[k].l>=a&&tree[k].r<=b) { ans+=tree[k].w; return ; } if(tree[k].f) down(k); int m=(tree[k].l+tree[k].r)>>1; if(a<=m) ask_interval(k<<1); if(b>m) ask_interval(k<<1|1); } int main() { n=read();m=read(); build(1,1,n); while(m--) { q=read();ans=0; if(q==1) { a=read(),b=read(),y=read(); change_interval(1); } else { a=read(),b=read(); ask_interval(1); printf("%lld\n",ans); } } return 0; }
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 100005 using namespace std; int n,m,c,a,b,x; long long ans,minn; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f; } struct Tree { int l,r; long long w,f; }tree[N<<2]; struct Node { int x,y,z; }node[N]; int cmp(Node a,Node b) { return a.y<b.y; } void build(int k,int l,int r) { tree[k].l=l,tree[k].r=r; if(tree[k].l==tree[k].r) { tree[k].w=c; return ; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); tree[k].w=min(tree[k<<1].w,tree[k<<1|1].w); } void down(int k) { tree[k<<1].f+=tree[k].f; tree[k<<1|1].f+=tree[k].f; tree[k<<1].w+=tree[k].f; tree[k<<1|1].w+=tree[k].f; tree[k].f=0; } void change(int k) { if(tree[k].l>=a&&tree[k].r<=b) { tree[k].w+=x; tree[k].f+=x; return ; } if(tree[k].f) down(k); int mid=(tree[k].r+tree[k].l)>>1; if(a<=mid) change(k<<1); if(b>mid) change(k<<1|1); tree[k].w=min(tree[k<<1].w,tree[k<<1|1].w); } void ask(int k) { if(tree[k].l>=a&&tree[k].r<=b) { minn=min(minn,tree[k].w); return ; } if(tree[k].f) down(k); int mid=(tree[k].r+tree[k].l)>>1; if(a<=mid) ask(k<<1); if(b>mid) ask(k<<1|1); } int main() { m=read(),n=read(),c=read(); build(1,1,n); for(int i=1;i<=m;i++) { node[i].x=read(),node[i].y=read(); node[i].z=read();node[i].y--; } sort(node+1,node+1+m,cmp); for(int i=1;i<=m;i++) { a=node[i].x,b=node[i].y; minn=0x7fffffff;ask(1); if(minn>node[i].z) x=-node[i].z,change(1),ans+=node[i].z; else x=-minn,change(1),ans+=minn; } printf("%lld",ans); }