• 算法复习——树链剖分模板(bzoj1036)


    题目:

    题目背景

    ZJOI2008 DAY1 T4

    题目描述

    一棵树上有 n 个节点,编号分别为 1 到 n ,每个节点都有一个权值 w 。
    我们将以下面的形式来要求你对这棵树完成一些操作:
    I.CHANGE u t :把结点 u 的权值改为 t ;
    II.QMAX u v :询问从点 u 到点 v 的路径上的节点的最大权值;
    III.QSUM u v :询问从点 u 到点 v 的路径上的节点的权值和。

    注意:从点 u 到点 v 的路径上的节点包括 u 和 v 本身。

    输入格式

    输入第一行为一个整数 n ,表示节点的个数。
    接下来 n–1 行,每行 2 个整数 a 和 b ,表示节点 a 和节点 b 之间有一条边相连。
    接下来 n 行,每行一个整数,第 i 行的整数 wi 表示节点 i 的权值。
    接下来 1 行,为一个整数 q ,表示操作的总数。
    接下来 q 行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

    输出格式

    对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

    样例数据 1

    输入  [复制]

     

    1 2 
    2 3 
    4 1 
    4 2 1 3 
    12 
    QMAX 3 4 
    QMAX 3 3 
    QMAX 3 2 
    QMAX 2 3 
    QSUM 3 4 
    QSUM 2 1 
    CHANGE 1 5 
    QMAX 3 4 
    CHANGE 3 6 
    QMAX 3 4 
    QMAX 2 4 
    QSUM 3 4

    输出





    10 




    16

    备注

    【数据范围】
    对于 100% 的数据,保证1<=n<=30000;0<=q<=200000;中途操作中保证每个节点的权值 w 在 -30000 到 30000 之间。

    方法:

     树链剖分模板题;

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=3e4+5;
    const int inf=1e+9;
    int n,Q;
    int first[N],next[N*2],go[N*2];
    int size[N],top[N],father[N],pos[N],idx[N],deep[N],tot,son[N],val[N];
    int summ[N*4],maxx[N*4];
    char st[100];
    
    inline void combin(int u,int v)
    {
      next[++tot]=first[u],first[u]=tot,go[tot]=v;
      next[++tot]=first[v],first[v]=tot,go[tot]=u;
    }
    
    inline void dfs1(int u)
    {
      size[u]=1;
      for(int e=first[u],v;e;e=next[e])
      {
        if((v=go[e])==father[u])  continue;  
        father[v]=u;
        deep[v]=deep[u]+1;
        dfs1(v);
        size[u]+=size[v];
        if(size[v]>size[son[u]])  son[u]=v;
      }
    }
    
    inline void dfs2(int u)
    {
      if(son[u])
      {
        idx[pos[son[u]]=++tot]=son[u];
        top[son[u]]=top[u];
        dfs2(son[u]);
      }
      for(int e=first[u],v;e;e=next[e])
      {
        if((v=go[e])==father[u]||v==son[u])  continue;
        idx[pos[v]=++tot]=v;
        top[v]=v;
        dfs2(v);
      }
    }
    
    inline void pre()
    {
      dfs1(1);
      top[1]=pos[1]=idx[1]=tot=1;
      dfs2(1);
    }
     
    inline void build(int k,int l,int r)
    {
      if(l==r)
      {
        summ[k]=maxx[k]=val[idx[l]];
        return;
      }
      int mid=(l+r)/2;
      build(k*2,l,mid);
      build(k*2+1,mid+1,r);
      summ[k]=summ[k*2]+summ[k*2+1];
      maxx[k]=max(maxx[k*2],maxx[k*2+1]);
    }
    
    inline void modify(int k,int l,int r,int p,int v)
    {
      if(l==r)
      {
        summ[k]=maxx[k]=v;
        return;
      }
      int mid=(l+r)/2;
      if(p<=mid)  modify(k*2,l,mid,p,v);
      else modify(k*2+1,mid+1,r,p,v);
      summ[k]=summ[k*2]+summ[k*2+1];
      maxx[k]=max(maxx[k*2],maxx[k*2+1]);
    }
    
    inline int querymax(int k,int l,int r,int x,int y)
    {
      if(l>=x&&r<=y)
        return maxx[k];
      int mid=(l+r)/2,res=-inf;
      if(x<=mid)  res=querymax(k*2,l,mid,x,y);
      if(y>mid)  res=max(res,querymax(k*2+1,mid+1,r,x,y));
      return res;
    }
     
    inline int querysum(int k,int l,int r,int x,int y)
    {
      if(l>=x&&r<=y)
        return summ[k];
      int mid=(l+r)/2,res=0;
      if(x<=mid)  res+=querysum(k*2,l,mid,x,y);
      if(y>mid)  res+=querysum(k*2+1,mid+1,r,x,y);
      return res;
    }
    
    inline int pathmax(int u,int v)
    {
      if(top[u]!=top[v])
      {
        if(deep[top[u]]<deep[top[v]])  swap(u,v);
        return max(pathmax(father[top[u]],v),querymax(1,1,n,pos[top[u]],pos[u])); 
      }
      if(deep[u]>deep[v])  swap(u,v);
        return querymax(1,1,n,pos[u],pos[v]);
    }
    
    inline int pathsum(int u,int v)
    {
      if(top[u]!=top[v])
      {
        if(deep[top[u]]<deep[top[v]])  swap(u,v);
        return pathsum(father[top[u]],v)+querysum(1,1,n,pos[top[u]],pos[u]); 
      }
      if(deep[u]>deep[v])  swap(u,v);
        return querysum(1,1,n,pos[u],pos[v]);
    }
    
    int main()
    {
      //freopen("a.in","r",stdin);
      //freopen("a.out","w",stdout);
      scanf("%d",&n);
      int u,v;
      for(int i=1;i<n;i++)
      {
        scanf("%d%d",&u,&v);
        combin(u,v);
      }
      for(int i=1;i<=n;i++)
        scanf("%d",&val[i]);
      pre();
      build(1,1,n);
      scanf("%d",&Q);
      while(Q--)
      {
        scanf("%s%d%d",st,&u,&v);
        if(st[1]=='M')
          printf("%d
    ",pathmax(u,v));
        if(st[1]=='S')
          printf("%d
    ",pathsum(u,v));
        if(st[1]=='H')
          modify(1,1,n,pos[u],v);
      }
      return 0;
    }
  • 相关阅读:
    Jupyter-notebook安装问题及解决
    [模块] scrapy_splash(迁移)
    pychram-redis破解
    scrapy-redis(迁移)
    123
    day44作业
    sql 的基本数据类型
    基本数据库操作
    安装数据库与配置使用环境
    线程知识点——Event事件
  • 原文地址:https://www.cnblogs.com/AseanA/p/7105210.html
Copyright © 2020-2023  润新知