1. 程式人生 > >【線段樹】Just a Hook

【線段樹】Just a Hook

區間更新,總區間求和

分析:

看到題目首先想到了線段樹,(因為題目是區間更新)區間更新需要用到延遲標記(或者說懶惰標記),簡單來說就是每次更新的時候不要更新到底,用延遲標記使得更新延遲到下次需要更新or詢問到的時候。延遲標記的意思是:這個區間的左右兒子都需要被更新,但是當前區間已經更新了。

節點中儲存的值代表這個區間的金屬成色(1-銅,2-銀,3-金;/如果這個區間還有其它成色,即雜色金屬,則值為-1。

原創程式碼


#include<string>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 100000
int sum,n,m,x,y,z;
struct node{
	int l,r,w;
}ac[maxn*4+1];//線段樹佔空間約為結點個數的 4 倍! 

void build(int k,int l,int r)
{
	ac[k].l=l;
	ac[k].r=r;
	ac[k].w=1;
	if(l==r){
		return ;
	}
	int mid=(ac[k].l+ac[k].r)/2;
	build(k*2,l,mid);
	build(k*2+1,mid+1,r);
}

//區間更新 
void up(int k,int l,int r,int v)
{
	if(ac[k].l==l && ac[k].r==r)
	{
		ac[k].w=v;
		return ;
	}
	
	if(ac[k].w==v)    
        return ;

	if(ac[k].w!=-1)//編號為k的區間都為純色 
	{    //下面附上顏色值 
         ac[2*k].w=ac[2*k+1].w=ac[k].w;
         ac[k].w=-1;
    }
	int mid=(ac[k].l+ac[k].r)/2;
	if(mid>=r)
	{
		up(k*2,l,r,v); 
	} 
	else if(mid<l)
	{
		up(k*2+1,l,r,v); 
	}
	 
	else{
		up(k*2,l,mid,v); 
		up(k*2+1,mid+1,r,v); 
	}
}

int query(int k,int l,int r){
	if(ac[k].w==-1)	return query(k*2,l,r)+query(k*2+1,l,r);
	else return (ac[k].r-ac[k].l+1)*ac[k].w;//編號k都是純色 
}

int main(){
	while(scanf("%d",&sum)!=EOF){
	for(int s=1;s<=sum;s++){
			scanf("%d%d",&n,&m);
			build(1,1,n);
			for(int i=1;i<=m;i++){
				scanf("%d%d%d",&x,&y,&z);
				up(1,x,y,z);
			}
			printf("Case %d: The total value of the hook is %d.\n",s,query(1,1,n));
		}
	}
	return 0;
}