1. 程式人生 > >3974 DFS建樹(DFS序)&線段樹

3974 DFS建樹(DFS序)&線段樹

寫了幾道線段樹的題目,感覺基礎線段樹的題目除了在更新和查詢上做一些文章以外,還有就是這種在建樹上設定一些門檻的題目了,感覺這道題目除了找dfs序列的過程就剩下裸的線段樹了。這個用dfs序建樹的過程,往往就是題目當中抽象成模型的重要過程。

題意:一棵樹的結構,父節點是老闆,子節點是員工,每次給父節點分配的任務,立即會下分到他所有的子節點,有更新和查詢命令。

解題過程:建立DFS序感覺對於這種需要用節點間前驅於後繼關係將節點串聯成圖的題目應該是關鍵的切入點,感覺這種思想是以後解題中很可能多次運用到的。

DFS序:由於題目給定的節點之間的關係可得一個樹以及樹的根節點,由根節點遍歷完整顆樹得到的序列就是dfs序。

為什麼要用dfs序建樹?

因為根據題目的需求,我需要就是可以將一個節點所包含的所有節點全部更新,這正好對應的就是線段樹操作中的區間更新,

怎樣才能線上段樹中區間更新一個節點的所有子節點呢?這個節點和他們的子節點必須連續

通過dfs序得到一個序列如果作為一顆線段樹最下層的子節點的話正好滿足這個要求,每個節點的所有子節點都跟在這個節點的後面,這種形式可以直接找到任何一個節點所包含所有子節點的區間,進行區間更新。

另外一點需要注意的就是,因為題目說每個人接到新工作就會停止手頭的工作,這個線段樹中不能通過任何一個根節點體現所包含節點的情況,所以必須查線段樹的最下層,就是查到每一個要查的節點而不是查到包含他的區間。

#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
struct node{
	int l,r;
	int work,lazy;
}tree[4*50005];
vector<int>map[50005];
int len,vis[50005],ll[50005],rr[50005];
void dfs(int x){
	++len;
	vis[x]=1;
	ll[x]=len;
	for(int i=0;i<map[x].size();i++){
		dfs(map[x][i]);
	}
	rr[x]=len;
}
void build(int i,int l,int r){
	tree[i].l=l;tree[i].r=r;
	tree[i].work=-1;tree[i].lazy=0;
	if(l==r)
		return;
	build(i<<1,l,(int)floor((r+l)/2.0));
	build((i<<1)+1,(int)floor((r+l)/2.0)+1,r);
}
void pushdown(int i){
	tree[i<<1].lazy=tree[(i<<1)+1].lazy=1;
	tree[i<<1].work=tree[(i<<1)+1].work=tree[i].work;
	tree[i].lazy=0;
}
int ans=0;
void que(int i,int id){
	if(tree[i].l==tree[i].r&&tree[i].l==id){
		ans=tree[i].work;
		return;
	}
	if(tree[i].lazy){
		pushdown(i);
	}
	int mid=(tree[i].l+tree[i].r)>>1;
	if(id<=mid){
		que(i<<1,id);
	}
	else{
		que((i<<1)+1,id);
	}
}
void update(int i,int l,int r,int w){
	if(tree[i].l>=l&&tree[i].r<=r){
		tree[i].work=w;
		tree[i].lazy=1;
		return;
	}
	if(tree[i].r<l||tree[i].l>r){
		return;
	}
	if(tree[i].lazy){
		pushdown(i)	;
	}
	update(i<<1,l,r,w);
	update((i<<1)+1,l,r,w);
}
int main(){
	int t,flag=1;
	cin>>t;
	while(t--){
		int n,m;
		cin>>n;
		len=0;
		memset(vis,0,sizeof(vis));
//        memset(ll,0,sizeof(ll));
//        memset(rr,0,sizeof(rr));
         for(int i=1;i<=n;i++)
            map[i].clear();
		for(int i=1;i<n;i++){
			int u,v;
			cin>>v>>u;
			map[u].push_back(v);
			vis[v]=1;
//			cout<<"asdf"<<endl;
		}
		for(int i=1;i<=n;i++){
			if(!vis[i]){
				dfs(i);
				break;
			}
		}
//		cout<<len<<endl;
		build(1,1,len);
		char s[5];
		cout<<"Case #"<<flag++<<":"<<endl;
		cin>>m;
		while(m--){
			cin>>s;		
			if(s[0]=='C'){
				int id;
				cin>>id;
				ans=-1;
				que(1,ll[id]);
				cout<<ans<<endl;
			}
			else{
				int id,wo;
				cin>>id>>wo;
				update(1,ll[id],rr[id],wo);
			}
		}
	}
	return 0;
}