1. 程式人生 > >[ SPOJ 375 ] Query on a tree

[ SPOJ 375 ] Query on a tree

truct 執行 code max else set query 操作 修改

\(\\\)

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;
}

[ SPOJ 375 ] Query on a tree