[ SPOJ Qtree1 ] Query on a tree
\(\\\)
Description
给定 \(n\) 个点的树,边按输入顺序编号为\(1,2,...n-1\) 。
现要求按顺序执行以下操作(共 \(m\) 次):
-
\(CHANGE\ i\ t_i\) 将第 \(i\) 条边权值改为 \(t_i\)
-
\(QUERY\ a\ b\) 询问从 \(a\) 点到 \(b\) 点路径上的最大边权
有多组测试数据,每组数据以 \(DONE\) 结尾
- \(n,m\le 10^5\)
\(\\\)
Solution
重链剖分,线段树维护。
把边权记录在深度较深的叶节点上,具体编号的处理可以利用邻接表存图的方式。
修改就直接找到对应节点时间戳改了就好。
查询找 \(Lca\) 的时候注意不要算上 \(Lca\) 的答案,因为那里记录的是 \(Lca\) 到其父节点的边权。
Updata 的时候把 dfn 手残写成 pos 调了一天
\(\\\)
Code
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100010
#define gc getchar
#define Rg register
#define mid ((l+r)>>1)
#define inf 2000000000
using namespace std;
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
int n,m,tot,hd[N],bl[N],val[N];
struct edge{int to,nxt,w;}e[N<<1];
inline void add(int u,int v,int w){
e[++tot].to=v; e[tot].w=w;
e[tot].nxt=hd[u]; hd[u]=tot;
}
int sz[N],f[N],d[N],son[N];
void dfs1(int u,int fa){
sz[u]=1; son[u]=0;
for(Rg int i=hd[u],v;i;i=e[i].nxt)
if((v=e[i].to)!=fa){
d[v]=d[u]+1; dfs1(v,u);
val[v]=e[i].w; bl[(i+1)/2]=v;
sz[u]+=sz[v]; f[v]=u;
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
int cnt,dfn[N],top[N],pos[N];
void dfs2(int u,int fa){
dfn[u]=++cnt;
pos[cnt]=u;
if(!top[u]) top[u]=u;
if(son[u]) top[son[u]]=top[u],dfs2(son[u],u);
for(Rg int i=hd[u],v;i;i=e[i].nxt)
if((v=e[i].to)!=fa&&v!=son[u]) dfs2(v,u);
}
struct segment{
int root,ptr;
inline int newnode(){return ++ptr;}
struct node{int ls,rs,mx;}c[N<<1];
inline void pushup(int rt){
c[rt].mx=max(c[c[rt].ls].mx,c[c[rt].rs].mx);
}
void build(int &rt,int l,int r){
rt=newnode();
if(l==r){
c[rt].mx=val[pos[l]];
return;
}
build(c[rt].ls,l,mid);
build(c[rt].rs,mid+1,r);
pushup(rt);
}
void updata(int rt,int l,int r,int p,int x){
if(l==r){c[rt].mx=x;return;}
if(p<=mid) updata(c[rt].ls,l,mid,p,x);
else updata(c[rt].rs,mid+1,r,p,x);
pushup(rt);
}
int query(int rt,int l,int r,int L,int R){
if(l>R||r<L) return 0;
if(l>=L&&r<=R) return c[rt].mx;
int res=-inf;
if(L<=mid) res=max(res,query(c[rt].ls,l,mid,L,R));
if(R>mid) res=max(res,query(c[rt].rs,mid+1,r,L,R));
return res;
}
}tree;
inline int lca(int u,int v){
if(u==v) return 0;
int res=-inf;
while(top[u]!=top[v]){
if(d[top[u]]>d[top[v]]) u^=v^=u^=v;
res=max(res,tree.query(tree.root,1,n,dfn[top[v]],dfn[v]));
v=f[top[v]];
}
if(d[u]>d[v]) u^=v^=u^=v;
res=max(res,tree.query(tree.root,1,n,dfn[u]+1,dfn[v]));
return res;
}
void work(){
n=rd(); cnt=tot=0;
memset(f,0,sizeof(f));
memset(hd,0,sizeof(hd));
memset(top,0,sizeof(top));
memset(val,0,sizeof(val));
for(Rg int i=1,u,v,w;i<n;++i){
u=rd(); v=rd(); w=rd();
add(u,v,w); add(v,u,w);
}
dfs1(1,0); dfs2(1,0);
tree.build(tree.root,1,n);
char c; int x,y;
while(1){
c=gc(); while(!isalpha(c)) c=gc();
if(c=='D') return;
if(c=='Q'){x=rd();y=rd();printf("%d\n",lca(x,y));}
else{x=rd();y=rd();tree.updata(tree.root,1,n,dfn[bl[x]],y);}
}
}
int main(){
int t=rd();
while(t--) work();
return 0;
}