• bzoj 2836 魔法树 —— 树链剖分


    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2836

    树链剖分裸题;

    写码五分钟,调码两小时,RE不断,狂交二十五遍,终于找到一处小细节——易错点!

    就是跳 top 时,不是按 dep[x] < dep[y] 交换 x,y,而要按 dep[top[x]] < dep[top[y]] 交换 x,y,否则就跳不到 lca 了!

    经验++。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define mid ((l+r)>>1)
    #define ls (x<<1)
    #define rs (x<<1|1)
    using namespace std;
    typedef long long ll;
    int const xn=100005;
    int n,fa[xn],hd[xn],ct,nxt[xn],to[xn],dfn[xn],tim,siz[xn],son[xn],top[xn],dep[xn];
    ll sum[xn<<2],lzy[xn<<2];
    char ch[10];
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
    void dfs(int x)
    {
      siz[x]=1; dep[x]=dep[fa[x]]+1;
      for(int i=hd[x],u;i;i=nxt[i])
        {
          dfs(u=to[i]);
          if(siz[u]>siz[son[x]])son[x]=u;
          siz[x]+=siz[u];
        }
    }
    void dfs2(int x)
    {
      dfn[x]=++tim;
      if(son[x])top[son[x]]=top[x],dfs2(son[x]);
      for(int i=hd[x],u;i;i=nxt[i])
        {
          if((u=to[i])==son[x])continue;
          top[u]=u; dfs2(u);
        }
    //  ed[x]=tim;
    }
    void pushdown(int x,int l,int r)
    {
      if(!lzy[x])return; 
      sum[ls]+=lzy[x]*(mid-l+1); lzy[ls]+=lzy[x];
      sum[rs]+=lzy[x]*(r-mid); lzy[rs]+=lzy[x];
      lzy[x]=0;
    }
    void update(int x,int l,int r,int L,int R,int k)
    {
      if(l>=L&&r<=R){sum[x]+=(ll)k*(r-l+1); lzy[x]+=k; return;}
      pushdown(x,l,r); 
      if(mid>=L)update(ls,l,mid,L,R,k);
      if(mid<R)update(rs,mid+1,r,L,R,k);
      sum[x]=sum[ls]+sum[rs];
    }
    ll query(int x,int l,int r,int L,int R)
    {
      if(l>=L&&r<=R)return sum[x];
      pushdown(x,l,r); ll ret=0;
      if(mid>=L)ret+=query(ls,l,mid,L,R);
      if(mid<R)ret+=query(rs,mid+1,r,L,R);
      return ret;
    }
    void add(int x,int y,int d)
    {
      while(top[x]!=top[y])
        {
          if(dep[top[x]]<dep[top[y]])swap(x,y);//!!!!!
          update(1,1,n,dfn[top[x]],dfn[x],d); x=fa[top[x]];
        }
      if(dep[x]<dep[y])swap(x,y);
      update(1,1,n,dfn[y],dfn[x],d);
    }
    int main()
    {
      n=rd();
      for(int i=1,x,y;i<n;i++)
        {
          x=rd()+1; y=rd()+1;
          fa[y]=x; add(x,y); 
        }
      dfs(1); top[1]=1; dfs2(1);
      int q=rd();
      for(int i=1,u,v,d;i<=q;i++)
        {
          scanf("%s",ch);
          if(ch[0]=='A')
        {
          u=rd()+1; v=rd()+1; d=rd();
          add(u,v,d);
        }
          else u=rd()+1,printf("%lld
    ",query(1,1,n,dfn[u],dfn[u]+siz[u]-1));    
        }
      return 0;
    }
  • 相关阅读:
    文化课随笔
    微积分与无穷级数
    [康复计划]-数论基础
    [Codeforces]CF742(Div.2)A-E
    第一次个人编程作业的过程和想法
    第一次个人编程作业
    Python命令行参数及文件读出写入
    第一次个人编程作业
    第一次个人编程作业
    第一次博客作业
  • 原文地址:https://www.cnblogs.com/Zinn/p/9801128.html
Copyright © 2020-2023  润新知