zoukankan      html  css  js  c++  java
  • Evanyou Blog 彩带

      题目传送门

    树链剖分

    题目描述

    这是一道模板题。

    给定一棵 n 个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值。下面依次进行 m 个操作,操作分为如下五种类型:

    • 换根:将一个指定的节点设置为树的新根。

    • 修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值。

    • 修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值。

    • 询问路径:询问某条路径上节点的权值和。

    • 询问子树:询问某个子树内节点的权值和。

    输入格式

    第一行为一个整数 n,表示节点的个数。

    第二行 nn个整数表示第 i 个节点的初始权值 ai​​。

    第三行 n1 个整数,表示i+1 号节点的父节点编号 $f_{i+1} (1 leqslant f_{i+1} leqslant n)$

    第四行一个整数 m,表示操作个数。

    接下来 m 行,每行第一个整数表示操作类型编号:$(1 leqslant u, v leqslant n)$

    • 若类型为 1,则接下来一个整数 u,表示新根的编号。

    • 若类型为 2,则接下来三个整数 u,v,k,分别表示路径两端的节点编号以及增加的权值。

    • 若类型为 3,则接下来两个整数 u,k,分别表示子树根节点编号以及增加的权值。

    • 若类型为 4,则接下来两个整数 u,v,表示路径两端的节点编号。

    • 若类型为 5,则接下来一个整数 u,表示子树根节点编号。

    输出格式

    对于每一个类型为 4 或 5 的操作,输出一行一个整数表示答案。

    样例

    样例输入

    6
    1 2 3 4 5 6
    1 2 1 4 4
    6
    4 5 6
    2 2 4 1
    5 1
    1 4
    3 1 2
    4 2 5

    样例输出

    15
    24
    19

    数据范围与提示

    对于 100% 的数据,$1leqslant n,m,k,a_ileqslant 10^5$​。数据有一定梯度。


      分析:

      虽然说是树剖模板,但是这个换根操作确实清奇。。。在集训的时候遇到了这题,当时反正是弃疗了。。。实际上换根操作并没有什么影响,在修改查询的时候判断一下就可以了。

      Code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e5+7;
    int n,m,root,a[N],head[N],cnt,fa[N],dep[N];
    int top[N],dfn[N],num[N],id,size[N],hson[N];
    struct Node{int to,next;}edge[N<<1];
    struct Seg{
      ll seg[N<<4],sign[N<<4];
      void pushup(int rt)
      {
        seg[rt]=seg[rt<<1]+seg[rt<<1|1];
      }
      void pushdown(int l,int r,int rt)
      {
        if(!sign[rt])return;
        int mid=(l+r)>>1;
        seg[rt<<1]+=sign[rt]*(mid-l+1);
        seg[rt<<1|1]+=sign[rt]*(r-mid);
        sign[rt<<1]+=sign[rt];
        sign[rt<<1|1]+=sign[rt];
        sign[rt]=0;
      }
      void build(int l,int r,int rt)
      {
        if(l>r)return;
        if(l==r){
          seg[rt]=a[dfn[l]];return;}
        int mid=(l+r)>>1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
        pushup(rt);
      }
      void update(int l,int r,int rt,int L,int R,ll C)
      {
        if(l>R||r<L)return;
        if(L<=l&&r<=R){
          seg[rt]+=(r-l+1)*C;sign[rt]+=C;return;}
        int mid=(l+r)>>1;
        pushdown(l,r,rt);
        if(L<=mid)update(l,mid,rt<<1,L,R,C);
        if(R>mid)update(mid+1,r,rt<<1|1,L,R,C);
        pushup(rt);
      }
      ll quary(int l,int r,int rt,int L,int R)
      {
        if(l>R||r<L)return 0;
        if(L<=l&&r<=R){return seg[rt];}
        int mid=(l+r)>>1;ll ret=0;
        pushdown(l,r,rt);
        if(L<=mid)ret+=quary(l,mid,rt<<1,L,R);
        if(R>mid)ret+=quary(mid+1,r,rt<<1|1,L,R);
        return ret;
      }
    }T;
    inline int read()
    {
      char ch=getchar();int num=0;bool flag=false;
      while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
      while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
      return flag?-num:num;
    }
    inline void add(int x,int y)
    {
      edge[++cnt].to=y;
      edge[cnt].next=head[x];
      head[x]=cnt;
    }
    inline void dfs1(int u)
    {
      size[u]=1;
      for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].to;if(v==fa[u])continue;
        fa[v]=u;dep[v]=dep[u]+1;
        dfs1(v);size[u]+=size[v];
        if(size[v]>size[hson[u]])hson[u]=v;
      }
    }
    inline void dfs2(int u,int now)
    {
      top[u]=now;num[u]=++id;dfn[id]=u;
      if(!hson[u])return;dfs2(hson[u],now);
      for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(v==fa[u]||v==hson[u])continue;
        dfs2(v,v);}
    }
    inline int check(int x)
    {
      if(x==root)return -1;
      if(!(num[x]<num[root]&&num[x]+size[x]-1>=num[root]))return 0;
      int now=root;
      while(dep[now]>dep[x]){if(fa[top[now]]==x)return top[now];now=fa[top[now]];}
      return hson[x];
    }
    inline void modify_path(int x,int y,ll z)
    {
      int fax=top[x],fay=top[y];
      while(fax!=fay){
        if(dep[fax]<dep[fay]){
          swap(fax,fay);swap(x,y);}
        T.update(1,n,1,num[fax],num[x],z);
        x=fa[fax];fax=top[x];}
      if(dep[x]>dep[y])swap(x,y);
      T.update(1,n,1,num[x],num[y],z);
    }
    inline int modify_tree(int x,ll y)
    {
      int ka=check(x);
      switch (ka){
      case -1:T.update(1,n,1,1,n,y);break;
      case 0:T.update(1,n,1,num[x],num[x]+size[x]-1,y);break;
      default:T.update(1,n,1,1,n,y);T.update(1,n,1,num[ka],num[ka]+size[ka]-1,-y);break;
      }
    }
    inline ll quary_path(int x,int y)
    {
      int fax=top[x],fay=top[y];ll ret=0;
      while(fax!=fay){
        if(dep[fax]<dep[fay]){
          swap(fax,fay);swap(x,y);}
        ret+=T.quary(1,n,1,num[fax],num[x]);
        x=fa[fax];fax=top[x];}
      if(dep[x]>dep[y])swap(x,y);
      ret+=T.quary(1,n,1,num[x],num[y]);
      return ret;
    }
    inline ll quary_tree(int x)
    {
      int ka=check(x);ll ret;
      switch (ka){
      case -1:ret=T.seg[1];break;
      case 0:ret=T.quary(1,n,1,num[x],num[x]+size[x]-1);break;
      default:ret=T.seg[1]-T.quary(1,n,1,num[ka],num[ka]+size[ka]-1);break;
      }
      return ret;
    }
    int main()
    {
      n=read();int x,y,z,opt;root=1;
      memset(head,-1,sizeof(head));
      for(int i=1;i<=n;i++)a[i]=read();
      for(int i=2;i<=n;i++){
        x=read();add(x,i);add(i,x);}
      dep[1]=1;dfs1(1);dfs2(1,1);
      T.build(1,n,1);m=read();
      for(int i=1;i<=m;i++){
        opt=read();
        if(opt==1){x=read();root=x;}
        else if(opt==2){
          x=read();y=read();z=read();
          modify_path(x,y,z);}
        else if(opt==3){
          x=read();y=read();
          modify_tree(x,y);}
        else if(opt==4){
          x=read();y=read();
          printf("%lld
    ",quary_path(x,y));}
        else {x=read();
          printf("%lld
    ",quary_tree(x));}}
      return 0;
    }
  • 相关阅读:
    高速传输线PCB设计
    带状线和微带线
    资源分配
    异步时钟切换电路
    Mathcad操作tips:2D绘图
    Mathcad操作tips:函数、符号计算
    慢性胃炎注意事项
    Arduino I2C + 三轴加速度计ADXL345
    Arduino SPI + SPI Flash芯片W25Q80BV
    Arduino I2C + 三轴加速度计LIS3DH
  • 原文地址:https://www.cnblogs.com/cytus/p/9225336.html
Copyright © 2011-2022 走看看