zoukankan      html  css  js  c++  java
  • 线段树模板

    首先是建树:

    const int MAXN = 1005;//定义 MAXM 为线段最大长度
    
    int Tree[4*MAXN];// Data数组为 main 函数中读入的内容,Tree数组为需要查询的数的信息(如和、最值等),树的空间大小为线段最大长度的四倍!四倍!四倍! 
    int Data[MAXN];
    
    void Build(int temp,int left,int right){//传入的参数为 temp:当前需要建立的结点;left:当前需要建立的左端点;right:当前需要建立的右端点。 
    	if(left==right){//当左端点等于右端点即建立叶子结点时,直接给数组信息赋值
    		Tree[temp] = Data[left];
    		return ;
    	}
    	int mid = left + (right-left)/2; // mid为中间点,左儿子结点为 [left,mid] ,右儿子结点为 [mid+1,right];
    	Build(temp<<1,left,mid);
    	Build(temp<<1|1,mid+1,right);
    	Tree[temp] = max(Tree[temp<<1],Tree[temp<<1|1]);//递归返回时用儿子结点更新父节点,此处可进行更新最大值、最小值、区间和等操作
    }

    单点修改以及对应的区间查询:

    void Updata(int temp,int left,int right,int tempt,int value){//tempt为需要修改的叶子结点左端点,value为需要修改成的值;
    	if(left == right){
    		Tree[temp] = value;
    		return ;
    	}
    	int mid = left + (right-left)/2;
    	if(tempt<=mid)Updata(temp<<1,left,mid,tempt,value);//若需要更新的叶子结点在当前结点的左儿子结点的范围内,则递归更新左儿子结点
    	else Updata(temp<<1|1,mid+1,right,tempt,value);//否则更新右儿子结点
    	Tree[temp] = max(Tree[temp<<1],Tree[temp<<1|1]);//递归回之后用儿子结点更新父节点(此处是区间最大值)
    }
    
    int query(int temp,int left,int right,int ql,int qr){//区间查询 
    	if(qr<left || ql>right)return -1;//若当前结点和需要查找的区间不相交,则返回一个对于区间查询无关的值(如求和时返回0,求最大值时返回-1等)
    	if(ql<=left && qr>=right)return Tree[temp]; //若当前结点的区间被需要查询的区间覆盖,则返回当前结点的信息
    	int mid = left + (right-left)/2;
    	return max(query(temp<<1,left,mid,ql,qr),query(temp<<1|1,mid+1,right,ql,qr));
    } 

    区间修改以及相应的查询:

    区间修改用到了lazy的思想,即当一个区间需要更新时,只递归更新到那一层结点,并将其下层结点所需要更新的信息保存在数组中,然后返回,只有当下次遍历到那个结点(更新过程中或查询过程中),才将那个结点的修改信息传递下去,这样就避免了区间修改的每个值的修改

    区间加值:

    int add[4*MAXN];//记录点是否有更新信息。 
    
    void Pushdown(int temp,int left,int right){//Pushdown函数,将temp结点的信息传递到左右子节点上
    	add[temp<<1] += add[temp]; //左右儿子结点均加上父节点的更新值
    	add[temp<<1|1] += add[temp];
    	int mid = left + (right-left)/2;
    	Tree[temp<<1] += add[temp]*(mid-left+1);//左右儿子结点均按照需要加的值总和更新结点信息
    	Tree[temp<<1|1] += add[temp]*(right-mid);
    	add[temp] = 0;//信息传递完之后就可以将父节点的更新信息删除
    }
    
    void Updata(int temp,int left,int right,int ql,int qr,int value){//ql、qr为需要更新的区间左右端点,value为需要增加的值。 
    	if(ql<=left && qr>=right){//与单点更新一样,当当前结点被需要更新的区间覆盖时
    		add[temp] += value; //更新该结点的更新信息
    		Tree[temp] += value*(right-left+1);//更新该结点信息
    		return ;//根据lazy思想,由于不需要遍历到下层结点,因此不需要继续向下更新,直接返回
    	} 
    	
    	if(add[temp])Pushdown(temp,left,right);
    	int mid = left + (right-left)/2;
    	if(ql<=mid)Updata(temp<<1,left,mid,ql,qr,value);//当需更新区间在当前结点的左儿子结点内,则更新左儿子结点
    	if(qr>mid)Updata(temp<<1|1,mid+1,right,ql,qr,value); //当需更新区间在当前结点的右儿子结点内,则更新右儿子结点
    	Tree[temp] = Tree[temp<<1]+Tree[temp<<1|1];//递归回上层时一步一步更新回父节点
    }
    
    long long query(int temp,int left,int right,int ql,int qr){ //ql、qr为需要查询的区间
    	if(ql<=left && qr>=right)return Tree[temp];//若当前结点覆盖区间即为需要查询的区间,则直接返回当前结点的信息
    	if(add[temp])PushDown(temp,left,right); //将当前结点的更新信息传递给其左右子节点
    	int mid = left + (right-left)/2;
    	long long ans = 0;						//所需查询的结果
    	if(ql<=m)ans += query(temp<<1,left,mid,ql,qr); //若所需查询的区间与当前结点的左子节点有交集,则结果加上查询其左子节点的结果
    	if(qr>m)ans += query(temp<<1|1,mid+1,right,ql,qr);//若所需查询的区间与当前结点的右子节点有交集,则结果加上查询其右子节点的结果
    	return ans;
    }

    区间改值(其实只是Pushdow函数和Update中修改部分与区间加值不同,并多了一个判断数组):

    int Change[4*MAXN];//记录节点改变信息 
    bool book[4*MAXN];//记录节点是否有改变要传递 
    
    void Pushdown(int temp,int left,int right){//Pushdown和区间加值不同,改值时修改结点信息只需要对修改后的信息求和即可,不用加上原信息
    	Change[temp<<1] = Change[temp];
    	Change[temp<<1|1] = Change[temp];
    	book[temp<<1] = true;
    	book[temp<<1|1] = true;
    	book[temp] = false;
    	int mid = left + (right-left)/2;
    	Tree[temp<<1] = Change[temp]*(mid-left+1);
    	Tree[temp<<1|1] = Change[temp]*(right-mid);
    }
    
    void Updata(int temp,int left,int right,int ql,int qr,int value){
    	if(ql<=left && qr>=right){				 //同样更新结点信息和区间加值不同
    		Change[temp] = value;
    		book[temp] = true;
    		Tree[temp] = value*(right-left+1);
    		return;
    	}
    	
    	if(book[temp])Pushdown(temp,left,right);
    	
    	int mid = left + (right-left)/2;
    	if(ql<=mid)Updata(temp<<1,left,mid,ql,qr,value);
    	if(qr>mid)Updata(temp<<1|1,mid+1,right,ql,qr,value);
    	
    	Tree[temp] = Tree[temp<<1]+Tree[temp<<1|1]; 
    } 
    
    long long query(int temp,int left,int right,int ql,int qr){
    	if(ql<=left && qr>=right)return Tree[temp];
    	if(book[temp])Pushdown(temp,left,right);
    	int mid = left + (right-left)/2;
    	long long ans = 0;
    	if(ql<=mid)ans += query(temp<<1,left,mid,ql,qr);
    	if(qr>mid)ans += query(temp<<1|1,mid+1,right,ql,qr);
    	return ans;
    }
    

    区间合并:

    const int MAXN = 100005;
    
    int Data[MAXN];
    int Change[MAXN*4];
    
    struct D{
    	int l;//从左边界点开始的最大连续 
    	int r;//从右边界点开始的最大连续
    	int maxn;//区间的最大连续(端点是左或右或左右边界点或没有)
    	int s;//区间的长度。 
    }Tree[MAXN*4];
    
    void Up(int temp){
    	Tree[temp].l = Tree[temp<<1].l;
    	if(Tree[temp<<1].l == Tree[temp<<1].s)Tree[temp].l += Tree[temp<<1|1].l;
    	Tree[temp].r = Tree[temp<<1|1].r;
    	if(Tree[temp<<1|1].r == Tree[temp<<1|1].s)Tree[temp].r += Tree[temp<<1].r;
    	Tree[temp].maxn = max(Tree[temp<<1].maxn,Tree[temp<<1|1].maxn);
    	Tree[temp].maxn = max(Tree[temp].maxn,Tree[temp<<1].r+Tree[temp<<1|1].l);
    }
    
    void Build(int temp,int left,int right){
    	Tree[temp].s = right-left+1;
    	if(left == right){
    		if(Data[left]){		/*这里一般是两种状态,具体根据题来改*/
    			Tree[temp].l = Tree[temp].r = Tree[temp].maxn = 1;
    		}else {
    			Tree[temp].l = Tree[temp].r = Tree[temp].maxn = 0;
    		}
    		return ;
    	}
    	int mid = left + (right-left)/2;
    	Build(temp<<1,left,mid);
    	Build(temp<<1|1,mid+1,right);
    	Up(temp);
    }
    
    void PushDown(int temp){
    	if(Change[temp]){
    		/*根据题要求写*/
    	}
    }
    
    void Updata(int temp,int left,int right,int ql,int qr){
    	if(ql<=left && qr>=right){
    		/*根据题要求写*/
    		return ;
    	}
    	
    	PushDown(temp);
    	
    	int mid = left + (right-left)/2;
    	if(ql<=mid)Updata(temp<<1,left,mid,ql,qr);
    	if(qr>mid)Updata(temp<<1|1,mid+1,right,ql,qr);
    	
    	Up(temp);
    } 
    
    int query(int temp,int left,int right,int ql,int qr){
    	if(ql==left && qr==right)return Tree[temp].maxn;
    	
    	PushDown(temp);
    	
    	int mid = left + (right-left)/2;
    	if(qr<=mid)return query(temp<<1,left,mid,ql,qr);
    	else if(ql>mid)return query(temp<<1|1,mid+1,right,ql,qr);
    	else {
    		int a,b,c;
    		a = query(temp<<1,left,mid,ql,mid);
    		b = query(temp<<1|1,mid+1,right,mid+1,qr);
    		c = min(mid-ql+1,Tree[temp<<1].r) + min(qr-mid,Tree[temp<<1|1].l);
    		return max(a,max(b,c));
    	}
    }
    


  • 相关阅读:
    Silverlight日记:动态操作Grid
    【转】cocos2dx 自学知识点之三 自定义动画 使用plist来实现
    Cocos2d-x的内存管理
    好色之徒
    freetype
    cocos2d 自定义字体
    cocos2d-x 内存管理
    VS2010 检查内存泄露的方法
    c++链表
    c/c++ time.h 那点事
  • 原文地址:https://www.cnblogs.com/vocaloid01/p/9514132.html
Copyright © 2011-2022 走看看