【lct】poj2763 Housewife Wind
题意:给你一棵树,边带权,支持两种操作:修改某条边的权值;查询两点之间的最短路。
lct主要实现单点修改和路径和。
修改x结点的值只需将x Splay到其所在辅助树的根,然后修改其值,再maintain一下即可。
路径和询问要这样做:
我们先 ACCESS(u), 然后在 ACCESS(v) 的过程中, 一旦 走到了包含根结点(也就是包含 u)的 Auxiliary Tree, 这时我们走到的结点恰好就是 u 和 v 的最近公共祖 先, 不妨称这个结点为 d. 这时 d 所在的 Auxiliary Tree 中 d 的右子树的 maxcost 即为 u 到 d 的路径的 最大边权, v 所在的 Auxiliary Tree 的 maxcost 则是 v 到 d 的路径的最大边权. 于是我们所求的答案就是 6 这两个 maxcost 中的最大值. 因为 Access 操作的均摊复杂度为 O(log n), 所以回答这个询问所花时间也 是 O(log n) 的.
Update:换了一种写法,能避免边权的鬼畜问题。即在每条边上添加一个虚点,权值为该边边权;而原先的所有点的点权置为零。这样虽然空间多了一倍,但是非常好处理了!(也即,询问可以用先ChangeRoot,再Access,再Splay,再询问左子树的方法了。)
代码更新在最下方。
<法一>
#include<cstdio> #include<iostream> #include<stack> #include<cstring> #include<algorithm> using namespace std; #define maxn 100005 int fa[maxn],c[maxn][2],siz[maxn]; bool is_root[maxn]; int val[maxn],totalval[maxn]; void Maintain(int x) { siz[x]=siz[c[x][0]]+siz[c[x][1]]+1; totalval[x]=totalval[c[x][0]]+totalval[c[x][1]]+val[x]; } void Rotate(int x,bool flag) { int y=fa[x]; c[y][!flag]=c[x][flag]; if(c[x][flag]){ fa[c[x][flag]]=y; } if(fa[y] && c[fa[y]][c[fa[y]][1]==y]==y){ c[fa[y]][c[fa[y]][1]==y]=x; } fa[x]=fa[y]; c[x][flag]=y; fa[y]=x; if(is_root[y]){ is_root[y]=0; is_root[x]=1; } Maintain(y); Maintain(x); } stack<int>st; void Splay(int x) { if(!x || is_root[x]){ return; } int y; while(y=fa[x],(!is_root[x])){ if(is_root[y]){ Rotate(x,c[y][0]==x); } else{ if((c[y][0]==x)==(c[fa[y]][0]==y)){ Rotate(y,c[fa[y]][0]==y); } else{ Rotate(x,c[y][0]==x); y=fa[x]; } Rotate(x,c[y][0]==x); } } Maintain(x); } void Spla2(int x) { if(!x || is_root[fa[x]]){ return; } int y; while(!is_root[y=fa[x]]){ if(is_root[fa[y]]){ Rotate(x,c[y][0]==x); } else{ if((c[y][0]==x)==(c[fa[y]][0]==y)){ Rotate(y,c[fa[y]][0]==y); } else{ Rotate(x,c[y][0]==x); y=fa[x]; } Rotate(x,c[y][0]==x); } } Maintain(x); } void Access(int x){ int y; Splay(x); while(fa[x]){ y=fa[x]; Splay(y); if(c[y][1]){ is_root[c[y][1]]=1; } is_root[x]=0; c[y][1]=x; Splay(x); } if(c[x][1]){ is_root[c[x][1]]=1; c[x][1]=0; } } int Calc(int x,int y){ if(x==y){ return 0; } Splay(y); if(!fa[y]){ Spla2(x); return totalval[c[x][0]]+val[x]; } int z; while(fa[y]){ z=fa[y]; Splay(z); if(!fa[z]){ return totalval[c[z][1]]+totalval[y]; } if(c[z][1]){ is_root[c[z][1]]=1; } is_root[y]=0; c[z][1]=y; Splay(y); } } int n,m,cur; int v[maxn<<1],nex[maxn<<1],first[maxn],w[maxn<<1],e; void AddEdge(int U,int V,int W){ v[++e]=V; w[e]=W; nex[e]=first[U]; first[U]=e; } int bel[maxn]; bool vis[maxn]; void dfs(int U){ vis[U]=1; for(int i=first[U];i;i=nex[i]){ if(!vis[v[i]]){ bel[i+1>>1]=v[i]; siz[v[i]]=1; is_root[v[i]]=1; val[v[i]]=totalval[v[i]]=w[i]; fa[v[i]]=U; dfs(v[i]); } } } int main(){ int op,x,y,z; // freopen("poj2763.in","r",stdin); // freopen("poj2763.out","w",stdout); scanf("%d%d%d",&n,&m,&cur); for(int i=1;i<n;++i){ scanf("%d%d%d",&x,&y,&z); AddEdge(x,y,z); AddEdge(y,x,z); } siz[1]=1; is_root[1]=1; dfs(1); for(int i=1;i<=m;++i){ scanf("%d%d",&op,&x); if(!op){ Access(x); printf("%d\n",Calc(x,cur)); cur=x; } else{ scanf("%d",&y); Splay(bel[x]); val[bel[x]]=y; Maintain(bel[x]); } } return 0; }
<法二>
#include<cstdio> #include<iostream> #include<stack> #include<cstring> #include<algorithm> using namespace std; #define maxn 200005 int fa[maxn],c[maxn][2],siz[maxn]; bool is_root[maxn],delta[maxn]; int val[maxn],totalval[maxn]; void Mark(int x){ if(x){ delta[x]^=1; } } void Maintain(int x) { siz[x]=siz[c[x][0]]+siz[c[x][1]]+1; totalval[x]=totalval[c[x][0]]+totalval[c[x][1]]+val[x]; } void pushdown(int x){ if(delta[x]){ Mark(c[x][0]); Mark(c[x][1]); swap(c[x][0],c[x][1]); delta[x]=0; } } void Rotate(int x,bool flag) { int y=fa[x]; c[y][!flag]=c[x][flag]; if(c[x][flag]){ fa[c[x][flag]]=y; } if(fa[y] && c[fa[y]][c[fa[y]][1]==y]==y){ c[fa[y]][c[fa[y]][1]==y]=x; } fa[x]=fa[y]; c[x][flag]=y; fa[y]=x; if(is_root[y]){ is_root[y]=0; is_root[x]=1; } Maintain(y); Maintain(x); } stack<int>st; void Splay(int x) { pushdown(x); if(!x || is_root[x]){ return; } int U=x; while(!is_root[U]){ st.push(U); U=fa[U]; } st.push(U); while(!st.empty()){ pushdown(st.top()); st.pop(); } int y; while(y=fa[x],(!is_root[x])){ if(is_root[y]){ Rotate(x,c[y][0]==x); } else{ if((c[y][0]==x)==(c[fa[y]][0]==y)){ Rotate(y,c[fa[y]][0]==y); } else{ Rotate(x,c[y][0]==x); y=fa[x]; } Rotate(x,c[y][0]==x); } } Maintain(x); } void Access(int x){ int y; Splay(x); while(fa[x]){ y=fa[x]; Splay(y); Splay(x); if(c[y][1]){ is_root[c[y][1]]=1; } is_root[x]=0; c[y][1]=x; Splay(x); } if(c[x][1]){ is_root[c[x][1]]=1; c[x][1]=0; } } void ChangeRoot(int x){ Access(x); Splay(x); Mark(x); } int QSum(int U,int V){ ChangeRoot(U); Access(V); Splay(V); return val[V]+totalval[c[V][0]]; } int v[maxn<<1],nex[maxn<<1],first[maxn],w[maxn<<1],e; void AddEdge(int U,int V,int W){ v[++e]=V; w[e]=W; nex[e]=first[U]; first[U]=e; } int tot,bel[maxn]; void dfs(int U){ for(int i=first[U];i;i=nex[i]){ if(!siz[v[i]]){ bel[i+1>>1]=++tot; siz[tot]=1; is_root[tot]=1; val[tot]=totalval[tot]=w[i]; fa[tot]=U; siz[v[i]]=1; is_root[v[i]]=1; val[v[i]]=totalval[v[i]]=0; fa[v[i]]=tot; dfs(v[i]); } } } int n,m,cur; int main(){ int op,x,y,z; // freopen("poj2763.in","r",stdin); scanf("%d%d%d",&n,&m,&cur); tot=n; for(int i=1;i<n;++i){ scanf("%d%d%d",&x,&y,&z); AddEdge(x,y,z); AddEdge(y,x,z); } siz[1]=1; is_root[1]=1; dfs(1); for(int i=1;i<=m;++i){ scanf("%d%d",&op,&x); if(!op){ printf("%d\n",QSum(x,cur)); cur=x; } else{ scanf("%d",&y); Splay(bel[x]); val[bel[x]]=y; Maintain(bel[x]); } } return 0; }
——The Solution By AutSky_JadeK From UESTC
转载请注明出处:http://www.cnblogs.com/autsky-jadek/