樹 (羅雨屏)倍增+dfs



試題來源


  IOI2012中國國家隊訓練
問題描述
  給定一棵大小爲 n 的有根點權樹,支持以下操作:
  • 換根
  • 修改點權


  • 查詢子樹最小值
輸入格式
  第一行兩個整數 n, Q ,分別表示樹的大小和操作數。
  接下來n行,每行兩個整數f,v,第i+1行的兩個數表示點i的父親和點i的權。保證f < i。如 果f = 0,那麼i爲根。輸入數據保證只有i = 1時,f = 0。



  接下來 m 行,爲以下格式中的一種:
  • V x y表示把點x的權改爲y

  • E x 表示把有根樹的根改爲點 x




  • Q x 表示查詢點 x 的子樹最小值
輸出格式
  對於每個 Q ,輸出子樹最小值。
樣例輸入
3 7
0 1
1 2
1 3
Q 1
V 1 6
Q 1
V 2 5
Q 1
V 3 4
Q 1
樣例輸出
1
2
3
4
數據規模和約定
  對於 100% 的數據:n, Q ≤ 10^5。



題目大意就是給你一棵樹,支持換根、修改點權、求一個點的子樹的最小值。

對於這道題,如果沒有換根操作,就直接上RMQ。

然而有了換根,我們可以先以1號點爲根處理出這棵樹的dfs序用線段樹來維護一段dfs序的最小值,修改點權就不說了。

對於每個查詢

設查詢的點X;

設此時根爲R;

設L[X]代表X在dfs序中第一次出現的位置

設R[X]代表X在dfs序中第一次出現的位置

如圖的一棵樹

1:當X等於R時 比如X=R=1

直接輸出整棵樹的最小值。



2:當R不在X的子樹中 比如X=2 R=3

明顯就是X的子樹中的最小值

即爲L[X]到R[X]的最小值



3:當X是R的祖先時

首先確定包含點的範圍:

舉兩個例子:當X=2、R=4時是1、2、3、5當X=1、R=4時是1、3。

通過這兩個例子,我們可以看出包含的範圍就是整棵樹除去E所在的子樹(E是X的兒子,也是R的祖先)。

那麼答案就是L[1]到L[E]-1與R[E]+1到R[1]的最小值

(這一點要仔細想想,當初也是花了好久才弄懂)

最後說一下幾個要注意的地方吧

求dfs序,不能直接dfs,會爆棧,所以。。。。手動棧吧

找E的時候不能一步一步往上跳,用倍增吧

Ps:其實上面兩點都不要管就可以過原始數據,只是我們oj喪心病狂處處卡人啊。。。。

轉自http://blog.csdn.net/abc473848880/article/details/13503533

但代碼不一樣哦


附代碼

#include<cmath>
#include<stack>
#include<cstdio>
#include<vector>
#include<utility>
using namespace std;
typedef pair<int,int> PII;
class Dread{
	public:
		int Int()            { int x;read(x);return x; }
		char Char()          { char ch;read(ch);return ch; }
	private:
		bool isdigit(char ch){ return ('0'<=ch && ch<='9'); }
		bool isalpha(char ch){ return ('a'<=ch && ch<='z') || ('A'<=ch && ch<='Z'); }
		void read(int &x){
			char ch;int tmp=0;
			while (ch=getchar()) if (isdigit(ch)) break;
			for (; isdigit(ch); ch=getchar()) tmp=tmp*10+ch-'0';
			x=tmp;
		}
		void read(char &ch){
			while (ch=getchar()) if (isalpha(ch)) break;
		}
}READ;
void swap(int &a,int &b){ int t=a;a=b;b=t; }
inline int min(int a,int b){ return a<b?a:b; }
const int N_MAX=100000+10,M_MAX=200000+10,K_MAX=20;
int now[N_MAX],pre[M_MAX],son[M_MAX],tot=0;
inline void add(int a,int b){ pre[++tot]=now[a];now[a]=tot;son[tot]=b; }
int N,Que,rt=1,val[N_MAX];
struct Ttree{
	struct SysInfo{
		int id,edge;   //id?????????? ,edge???????????????? 
		SysInfo(){}
		SysInfo(int _id,int _edge):id(_id),edge(_edge){}
	};
	vector<int> dfn;stack<SysInfo> stk;
	int anc[N_MAX][K_MAX],dep[N_MAX];PII app[N_MAX];
	void dfs(){
		stk.push(SysInfo(1,-1));dfn.push_back(1);app[1].first=dfn.size()-1;
		while (!stk.empty()){
			SysInfo top=stk.top();int p;
			for (p=top.edge==-1?now[top.id]:pre[top.edge]; p; p=pre[p]){
				stk.pop();stk.push(SysInfo(top.id,p));
				dep[son[p]]=dep[top.id]+1;
				anc[son[p]][0]=top.id;
				for (int tmp=top.id,k=0; anc[tmp][k]; ++k){
					anc[son[p]][k+1]=anc[tmp][k];
					tmp=anc[tmp][k];
				}
				stk.push(SysInfo(son[p],-1));
				dfn.push_back(son[p]);
				app[son[p]].first=dfn.size()-1;
				break;
			}
			if (!p) dfn.push_back(top.id),stk.pop(),app[top.id].second=dfn.size()-1;
		}
	}
	void dfs(int x){  //???????????????????????? 
		dfn.push_back(x);app[x].first=dfn.size()-1;
		for (int p=now[x]; p; p=pre[p]){
			dep[son[p]]=dep[x]+1;
			anc[son[p]][0]=x;
			for (int tmp=x,k=0; anc[tmp][k]; ++k){
				anc[son[p]][k+1]=anc[tmp][k];
				tmp=anc[tmp][k];
			}
			dfs(son[p]);
		}
		dfn.push_back(x);app[x].second=dfn.size()-1;
	}
	int Lca(int x,int y){
		if (x==y) return x;
		if (dep[x]<dep[y]) swap(x,y);
		int xdep=dep[x]-dep[y];
		for (int k=0; xdep; ++k){
			if (xdep%2) x=anc[x][k];
			xdep/=2;
		}
		if (x==y) return x;
		for (int k=0; x!=y; ){
			if (anc[x][k]!=anc[y][k] || (anc[x][k]==anc[y][k] && !k)){
				x=anc[x][k];y=anc[y][k];
				++k;
			}
			else --k;
		}
		return x;
	}
	int find(int x,int y){  //????x????y???????????????? 
		int xdep=dep[x]-dep[y]-1;
		for (int k=0; xdep; ++k){
			if (xdep%2) x=anc[x][k];
			xdep/=2;
		}
		return x;
	}
}TREE;
class Tseg{
	public:
		int size;
		void Build()            { build(1,0,size=TREE.dfn.size()-1); }
		int Query(int l,int r)  { return query(1,0,size,l,r); }
		void Modify(int x,int y){ modify(1,0,size,x,y); }
	private:
		int t[16*N_MAX];
		#define ls p*2
		#define rs p*2+1
		#define Lson p*2,l,mid
		#define Rson p*2+1,mid+1,r
		void update(int p){ t[p]=min(t[ls],t[rs]); }
		void build(int p,int l,int r){
			if (l==r){
				t[p]=val[TREE.dfn[l]];
				return;
			}
			int mid=(l+r)/2;
			build(Lson);build(Rson);
			update(p);
		}
		int query(int p,int l,int r,int fir,int lst){
			if (l==fir && r==lst) return t[p];
			int mid=(l+r)/2;
			if (lst<=mid) return query(Lson,fir,lst);
			else if (fir>mid) return query(Rson,fir,lst);
			else return min(query(Lson,fir,mid),query(Rson,mid+1,lst));
		}
		void modify(int p,int l,int r,int pos,int val){
			if (l==pos && r==pos){ t[p]=val; return; }
			int mid=(l+r)/2;
			if (pos<=mid) modify(Lson,pos,val);
			else modify(Rson,pos,val);
			update(p);
		}
}SEG;
int main(){
	N=READ.Int();Que=READ.Int();
	for (int i=1; i<=N; ++i){
		int fa=READ.Int();val[i]=READ.Int();
		if (fa) add(fa,i);
	}
	TREE.dfs();
	SEG.Build();
	for (int i=1; i<=Que; ++i){
		char opt=READ.Char();
		if (opt=='Q'){
			int x=READ.Int();
			if (x==rt) printf("%d\n", SEG.Query(0,SEG.size));
			else{
				int ancestor=TREE.Lca(rt,x);
				if (ancestor!=x) printf("%d\n", SEG.Query(TREE.app[x].first,TREE.app[x].second));
				else{
					int far=TREE.find(rt,x);
				//	printf("         %d %d %d\n",far,TREE.app[far].first-1,TREE.app[far].second+1);
					printf("%d\n", min(SEG.Query(0,TREE.app[far].first-1),
					SEG.Query(TREE.app[far].second+1,SEG.size)));
				}
			}
		}
		else if (opt=='E'){
			int newrt=READ.Int();
			rt=newrt;
		}
		else{
			int x=READ.Int(),y=READ.Int();
			SEG.Modify(TREE.app[x].first,y);
			SEG.Modify(TREE.app[x].second,y);
		}
	}
	//system("pause");
	return 0;
}

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