算法总结—线段树

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);
	}
}


猜你喜欢

转载自blog.csdn.net/ufo___/article/details/80037608