• ●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
    ",DT.Query(a,b));
    			else if(cmd[0]=='C') DT.Change(a,b);
    			else DT.Negate(a,b);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    java的集合框架不得不说
    Java集合框架学习总结
    Java集合框架的知识总结(1)
    Java集合框架1
    Java中常见的集合框架
    Java中的集合框架
    浅谈JAVA集合框架
    Java集合框架 看过来
    My Dream---------0.001版本
    数组(插入算法[int])
  • 原文地址:https://www.cnblogs.com/zj75211/p/8365707.html
Copyright © 2020-2023  润新知