●POJ 3237 Tree

Posted *ZJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了●POJ 3237 Tree相关的知识,希望对你有一定的参考价值。

题链:

http://poj.org/problem?id=3237

题解:

LCT

说一说如何完成询问操作就好了(把一条链的边权变成相反数的操作可以类比着来):

首先明确一下,我们把边权下放到点上。

(由于不存在合并,即不需要MovetoRoot操作,也就是说不需要改变树的形态,让它成为以1为根的有根树即可)

对于询问的a,b之间链上的最大值,

我们首先调用Access(b)函数,让b和根之间形成一条重链,

然后对x=a执行类似Access的过程,直到某一刻发现fa[x]==0时,

则表明现在的x是在b到根的路径上,或者说,此时的x点是a,b的最近公共祖先lca,

所以直接返回y子树和ch[x][1]子树的最大值就好了。

建议结合代码理解:

int Query(int x,int y){
	static int ret; Access(y);
	for(y=0;x;y=x,x=fa[x]){
		Splay(x);
		if(fa[x]) ch[x][1]=y;
		else ret=max(maxi[y],maxi[ch[x][1]]);
		Pushup(x);
	}
	return ret;
}

其他就没什么好说的了,都比较常规。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 10050
#define INF 0x3f3f3f3f
using namespace std;
struct Edge{
	int to[MAXN*2],nxt[MAXN*2],val[MAXN*2],head[MAXN],ent;
	void Reset(){ent=2; memset(head,0,sizeof(head));}
	void Adde(int u,int v,int w){
		to[ent]=v; val[ent]=w; 
		nxt[ent]=head[u]; head[u]=ent++;
	}
}E;
int belong[MAXN];
int Case,N;
struct LCT{
	int ch[MAXN][2],fa[MAXN];
	int maxi[MAXN],mini[MAXN],w[MAXN],lazy[MAXN];
	void Reset(){
		memset(ch,0,sizeof(ch));
		memset(lazy,0,sizeof(lazy));
		maxi[0]=-INF; mini[0]=INF;
	}
	bool Which(int x){return ch[fa[x]][1]==x;}
	bool Isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
	void Pushup(int x){
		maxi[x]=max(w[x],max(maxi[ch[x][0]],maxi[ch[x][1]]));
		mini[x]=min(w[x],min(mini[ch[x][0]],mini[ch[x][1]]));
	}
	void Opposite(int x){
		
		w[x]*=-1; maxi[x]*=-1; mini[x]*=-1;
		swap(maxi[x],mini[x]);
		lazy[x]^=1;
	}
	void Pushdown(int x){
		if(!Isroot(x)) Pushdown(fa[x]);
		if(!lazy[x]) return;
		Opposite(ch[x][0]); Opposite(ch[x][1]);
		lazy[x]^=1;
	}
	void Rotate(int x){
		static int y,z,l1,l2;
		y=fa[x]; z=fa[y]; 
		l1=Which(x); l2=Which(y); fa[x]=z;
		if(!Isroot(y)) ch[z][l2]=x;
		fa[ch[x][l1^1]]=y; fa[y]=x;
		ch[y][l1]=ch[x][l1^1]; ch[x][l1^1]=y;
		Pushup(y);
	}
	void Splay(int x){
		static int y; Pushdown(x);
		for(;y=fa[x],!Isroot(x);Rotate(x))
			if(!Isroot(y)) Rotate(Which(x)==Which(y)?y:x);
		Pushup(x);
	}
	void Access(int x){
		static int y;
		for(y=0;x;y=x,x=fa[x])
			Splay(x),ch[x][1]=y,Pushup(x);
	}
	void Change(int i,int v){
		static int x; x=belong[i];
		Splay(x); w[x]=v; Pushup(x);
	}
	void Negate(int x,int y){
		Access(y);
		for(y=0;x;y=x,x=fa[x]){
			Splay(x);
			if(fa[x]) ch[x][1]=y;
			else Opposite(y),Opposite(ch[x][1]);
			Pushup(x);
		}
	}
	int Query(int x,int y){
		static int ret; Access(y);
		for(y=0;x;y=x,x=fa[x]){
			Splay(x);
			if(fa[x]) ch[x][1]=y;
			else ret=max(maxi[y],maxi[ch[x][1]]);
			Pushup(x);
		}
		return ret;
	}
}DT;
void DFS(int u,int dad){
	DT.fa[u]=dad;
	for(int i=E.head[u];i;i=E.nxt[i]){
		int v=E.to[i]; if(v==dad) continue;
		belong[i>>1]=v; DT.maxi[v]=DT.mini[v]=DT.w[v]=E.val[i];
		DFS(v,u);
	}
}
int main(){
	int a,b,c; char cmd[10];
	for(scanf("%d",&Case);Case;Case--){
		DT.Reset(); E.Reset();
		scanf("%d",&N);
		for(int i=1;i<N;i++){
			scanf("%d%d%d",&a,&b,&c);
			E.Adde(a,b,c); E.Adde(b,a,c);
		}
		DFS(1,0);
		while(~scanf("%s",cmd)){
			if(cmd[0]==‘D‘) break;
			scanf("%d%d",&a,&b);
			if(cmd[0]==‘Q‘) printf("%d\n",DT.Query(a,b));
			else if(cmd[0]==‘C‘) DT.Change(a,b);
			else DT.Negate(a,b);
		}
	}
	return 0;
}

  

以上是关于●POJ 3237 Tree的主要内容,如果未能解决你的问题,请参考以下文章

POJ3237Tree 树链剖分+线段树

poj3237 Tree

●POJ 3237 Tree

poj 3237 Tree(树链剖分,线段树)

[POJ3237]Tree

POJ 3237 (Tree)