题链:
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; }