• [ 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,mle 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
    ",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;
    }
    
  • 相关阅读:
    9.5---所有字符串的排列组合(CC150)
    9.4---集合子集(CC150)
    9.3---魔术索引(CC150)
    5.3(2)----机器人走方格2(CC150)
    9.2---机器人走方格(CC150)
    9.1---上楼梯(CC150)
    5.3---找最近的两个数(CC150)
    5.8---像素设定(CC150)
    7.4---加法替代运算(CC150)
    4.9---二叉树路径和(CC150)
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9906008.html
Copyright © 2020-2023  润新知