码迷,mamicode.com
首页 > 其他好文 > 详细

●POJ 3237 Tree

时间:2018-01-27 15:18:20      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:problem   lazy   while   query   can   ring   操作   opp   ini   

题链:

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

标签:problem   lazy   while   query   can   ring   操作   opp   ini   

原文地址:https://www.cnblogs.com/zj75211/p/8365707.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!