算法總結—線段樹

HDU1556點擊打開鏈接

比較簡單的一道題,直接查詢的時候從上到下把value累加就行。

//hdu 1556 線段樹 單點查詢 
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
int N;
typedef struct node {
	int value;
	int left,right;
}node;
node tree[100000*8+5];//有時候開4倍的數組有時候8倍 這個開四倍會越界 

void build(int p,int l,int r) {
	tree[p].value=0;
	tree[p].left=l; 
	tree[p].right=r;
	if(l<r) {
		build(p*2,l,(l+r)/2);
		build(p*2+1,(l+r)/2+1,r);
	}
}

void add(int p,int l,int r,int v) {
	if(r<tree[p].left||l>tree[p].right) {
		return;
	}
	if(l<=tree[p].left&&r>=tree[p].right) {
		tree[p].value+=v;
	}else {
		add(p*2,l,r,v);
		add(p*2+1,l,r,v);
	}
}

int query(int p,int it) {
	if(it<tree[p].left||tree[p].right<it) {
		return 0;
	}
	return tree[p].value+query(p*2,it)+query(p*2+1,it);
}

int main() {
	while(cin>>N&&N) {
		build(1,1,N);
		int a,b;
		for(int i=1;i<=N;i++) {
			scanf("%d%d",&a,&b);
			add(1,a,b,1);
		}
		for(int i=1;i<=N;i++) {
			if(i!=N) printf("%d ",query(1,i));
			else printf("%d\n",query(1,i));
		}
	}
}

HDU1754點擊打開鏈接

單點更新,更新完子節點之後記得把父節點的值也更新。

//hdu 1754 線段樹 區間查詢 單點更新
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
int MING=-1;
typedef struct node {
	int maxg;
	int left,right;
}node;
node tree[8*200000+5];

int N,M;
int grades[200000+5];

int build(int p,int l,int r) {
	tree[p].left=l;
	tree[p].right=r;
	if(l==r) {
		return tree[p].maxg=grades[l];
	}else {
		int maxg=max(build(p*2,l,(l+r)/2),build(p*2+1,(l+r)/2+1,r));
		return tree[p].maxg=maxg;
    }
}

int query(int p,int l,int r) {
	if(tree[p].left>r||tree[p].right<l) {
		return MING;
	}else {
		if(tree[p].left>=l&&tree[p].right<=r) {
			return tree[p].maxg;
		}else {
			return max(query(p*2,l,r),query(p*2+1,l,r));
		}
	}
}

int update(int p,int it,int k) {
	if(tree[p].left==tree[p].right&&tree[p].left==it) {
		return tree[p].maxg=k;
	} else {
		int v;
		if(it<=(tree[p].left+tree[p].right)/2) {
			v=update(p*2,it,k);
		}else {
			v=update(p*2+1,it,k);
		}
		return tree[p].maxg=max(v,tree[p].maxg);//遞歸返回的時候更新父節點的值 
	}
}

int main() {
	while(scanf("%d%d",&N,&M)==2) {
		for(int i=1;i<=N;i++) {
			scanf("%d",&grades[i]);
		}
		build(1,1,N);
		
		char c; 
		int a,b;
	
		for(int i=1;i<=M;i++) {
			getchar();
			scanf("%c%d%d",&c,&a,&b);
			if(c=='Q') {
				printf("%d\n",query(1,a,b));
			}else {
				update(1,a,b);
			}
		}
	}
	
}

HDU1698點擊打開鏈接

加一個延遲標記delay即可,每次進入節點的時候都更新自己並且清除標記然後在把延遲標記往下傳,自己更新之後對子樹做延遲。

//hdu 1698 線段樹 區間更新 延遲標記
//debug update裏面又把 l r 給手賤分割了 直接傳下即可 建樹的時候纔要分割 
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
int T,N,Q;

typedef struct node {
	int values;
	int left,right;
	int delay;
}node;
node tree[100000*4+5];

void build(int p,int l,int r) {
	tree[p].left=l;
	tree[p].right=r;
	tree[p].values=r-l+1;
	tree[p].delay=0;
	if(l<r) {
		build(p*2,l,(l+r)/2);
		build(p*2+1,(l+r)/2+1,r);
	}
}

int update(int p,int l,int r,int v) {
	if(tree[p].delay!=0) {//做加載 
		tree[p].values=(tree[p].right-tree[p].left+1)*tree[p].delay;
		if(tree[p].left!=tree[p].right) {//把延遲標記傳遞給子樹並清除自己的延遲標記 
			tree[p*2].delay=tree[p].delay;
			tree[p*2+1].delay=tree[p].delay;
		}
		tree[p].delay=0;
	}
	
	if(r<tree[p].left||l>tree[p].right) {
		return tree[p].values;
	}
	
	if(l<=tree[p].left&&r>=tree[p].right) {
		tree[p].values=(tree[p].right-tree[p].left+1)*v;
		
		if(tree[p].left!=tree[p].right) {//給子樹做延遲
			tree[p*2].delay=v;
			tree[p*2+1].delay=v;
		}
		
		return tree[p].values;
	}else {
		int vl=update(p*2,l,r,v);
		int vr=update(p*2+1,l,r,v);
		tree[p].values=vl+vr;
		return tree[p].values;
	}
}

int main() {
	scanf("%d",&T);
	for(int Case=1;Case<=T;Case++) {
		scanf("%d%d",&N,&Q);
		build(1,1,N);
		int x,y,z;
		for(int i=1;i<=Q;i++) {
			scanf("%d%d%d",&x,&y,&z);
			update(1,x,y,z);
			//cout<<"v1="<<tree[1].values<<endl;
		}
		printf("Case %d: The total value of the hook is %d.\n",Case,tree[1].values);
	}
}

HDU1542點擊打開鏈接

老套路了,更新的時候直接更新到葉子節點即可。

//hdu 1542 線段樹 離散化 掃描線
//求並面積 
//注意 這裏線段樹的每個葉子管理的是一個元線段 而不是一個點
//所以 build 裏的 l+1<r 已及 update 裏的 tree[p].left+1==tree[p].right
//都要十分注意
//更新的時候直接更新到葉子節點即可 當然更新一次的時間複雜理論上屆是 nlogn
//但是不影響AC [Accepted	1542	0MS	1960K	2046 B	C++]
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
int N;

typedef struct line {
	double left,right;
	double high;
	int sp;
	bool operator < (const line & l) const {
		return high<l.high;
	}
}line;
double ser[505];//把橫座標離散化出來 
vector<line> ls;//把所有的線按high排序

typedef struct node {
	int left,right;
	int cover;
}node;
node tree[100*8+5];

void build(int p,int l,int r) {
	tree[p].left=l;
	tree[p].right=r;
	tree[p].cover=0;
	if(l+1<r) {
		build(p*2,l,(l+r)/2);
		build(p*2+1,(l+r)/2,r);
	}
}

double update(int p,line l) {

	if(l.right<=ser[tree[p].left]||l.left>=ser[tree[p].right]) {
		return 0;
	}
	
	if(tree[p].left+1==tree[p].right&&l.left<=ser[tree[p].left]&&l.right>=ser[tree[p].right]) {
		int c1=tree[p].cover;
		tree[p].cover+=l.sp;
		int c2=tree[p].cover;
		
		if(c1==0&&c2==1) {
			return ser[tree[p].right]-ser[tree[p].left];
		}else if(c1==1&&c2==0) {
			return -(ser[tree[p].right]-ser[tree[p].left]);
		}else {
			return 0;
		}
	}else {
		return update(p*2,l)+update(p*2+1,l);
	}
	
}

int main() {
	int Case=0; 
	while(cin>>N&&N) {
		Case++;
		ls.clear();
		double x1,y1,x2,y2;
		int pos=1;
		for(int i=1;i<=N;i++) {
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			line l1,l2;
			l1.left=x1,l1.right=x2,l1.high=y1,l1.sp=1;
			l2.left=x1,l2.right=x2,l2.high=y2,l2.sp=-1;
			ls.push_back(l1),ls.push_back(l2);
	        ser[pos++]=x1,ser[pos++]=x2;
		}
		sort(&ser[1],&ser[2*N+1]);
		sort(ls.begin(),ls.end());
	
		build(1,1,2*N);
		
		double len=0,s=0;
		for(int i=0;i<ls.size()-1;i++) {
			len+=update(1,ls[i]);
			s+=len*(ls[i+1].high-ls[i].high);
		}
		printf("Test case #%d\n",Case);
		printf("Total explored area: %.2f\n\n",s);
	}
}
HDU1255點擊打開鏈接
代碼都直接複製的1542。。。

//hdu 1255 線段樹 離散化 掃描線
//求交面積 
//注意 這裏線段樹的每個葉子管理的是一個元線段 而不是一個點
//直接把hdu1542的代碼copy來,修改一下cover的計數標準就行了 數組大小 答案四捨五入 
//      if(c1==1&&c2==2) {
//			do sometings 
//		}else if(c1==2&&c2==1) {
//			do sometings
//		}
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
int T,N;

typedef struct line {
	double left,right;
	double high;
	int sp;
	bool operator < (const line & l) const {
		return high<l.high;
	}
}line;
double ser[4005];//把橫座標離散化出來 
vector<line> ls;//把所有的線按high排序

typedef struct node {
	int left,right;
	int cover;
}node;
node tree[1000*8+5];

void build(int p,int l,int r) {
	tree[p].left=l;
	tree[p].right=r;
	tree[p].cover=0;
	if(l+1<r) {
		build(p*2,l,(l+r)/2);
		build(p*2+1,(l+r)/2,r);
	}
}

double update(int p,line l) {

	if(l.right<=ser[tree[p].left]||l.left>=ser[tree[p].right]) {
		return 0;
	}
	
	if(tree[p].left+1==tree[p].right&&l.left<=ser[tree[p].left]&&l.right>=ser[tree[p].right]) {
		int c1=tree[p].cover;
		tree[p].cover+=l.sp;
		int c2=tree[p].cover;
		
		if(c1==1&&c2==2) {
			return ser[tree[p].right]-ser[tree[p].left];
		}else if(c1==2&&c2==1) {
			return -(ser[tree[p].right]-ser[tree[p].left]);
		}else {
			return 0;
		}
	}else {
		return update(p*2,l)+update(p*2+1,l);
	}
	
}

int main() {
	cin>>T;
	while(T--) {
		ls.clear();
		double x1,y1,x2,y2;
		int pos=1;
		cin>>N;
		for(int i=1;i<=N;i++) {
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			line l1,l2;
			l1.left=x1,l1.right=x2,l1.high=y1,l1.sp=1;
			l2.left=x1,l2.right=x2,l2.high=y2,l2.sp=-1;
			ls.push_back(l1),ls.push_back(l2);
	        ser[pos++]=x1,ser[pos++]=x2;
		}
		sort(&ser[1],&ser[2*N+1]);
		sort(ls.begin(),ls.end());
	
		build(1,1,2*N);
		
		double len=0,s=0;
		for(int i=0;i<ls.size()-1;i++) {
			len+=update(1,ls[i]);
			s+=len*(ls[i+1].high-ls[i].high);
		}
		if(int(s*1000)%10>=5) {
			s+=0.01;
		}
		printf("%.2f\n",s);
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章