zoukankan      html  css  js  c++  java
  • bzoj 4034 [HAOI2015]树上操作——树链剖分

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

    这么赤裸裸的树剖竟然花了我这么久……

    就是因为树剖本来就是dfs序,所以就能弄子树了。每个节点return的时候记录一下表示自己子树的结束。注意这些都是在dfs2里的。

    注意各种 long long。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int N=1e5+5;
    int n,m,hd[N],xnt,son[N],siz[N],dfn[N],cq[N],id[N],top[N],fa[N],tim;
    int ls[N<<1],rs[N<<1];//
    ll sum[N<<1],lazy[N<<1],len[N<<1],val[N];//
    struct Ed{
      int nxt,to;Ed(int n=0,int t=0):nxt(n),to(t) {}
    }ed[N<<1];
    void add(int x,int y)
    {
      ed[++xnt]=Ed(hd[x],y);hd[x]=xnt;
      ed[++xnt]=Ed(hd[y],x);hd[y]=xnt;
    }
    void dfs1(int cr)
    {
      siz[cr]=1;
      for(int i=hd[cr],v;i;i=ed[i].nxt)
        if((v=ed[i].to)!=fa[cr])
          {
        fa[v]=cr;dfs1(v);siz[cr]+=siz[v];
        if(siz[v]>siz[son[cr]])son[cr]=v;
          }
    }
    void dfs2(int cr)
    {
      id[dfn[cr]=++tim]=cr;// not in dfs1!!!
      if(son[cr])top[son[cr]]=top[cr],dfs2(son[cr]);
      for(int i=hd[cr],v;i;i=ed[i].nxt)
        if((v=ed[i].to)!=fa[cr]&&v!=son[cr])
          top[v]=v,dfs2(v);
      cq[cr]=tim;
    }
    void pshp(int cr)
    {
      sum[cr]=sum[ls[cr]]+sum[rs[cr]];
    }
    void build(int l,int r,int cr)
    {
      len[cr]=r-l+1;
      if(l==r)
        {
          sum[cr]=val[id[l]];return;
        }
      int mid=((l+r)>>1);
      ls[cr]=++tim;build(l,mid,ls[cr]);
      rs[cr]=++tim;build(mid+1,r,rs[cr]);
      pshp(cr);
    }
    void pshd(int cr)
    {
      if(!lazy[cr])return;int l=ls[cr],r=rs[cr];
      ll w=lazy[cr];lazy[cr]=0;lazy[l]+=w;lazy[r]+=w;
      sum[l]+=len[l]*w;sum[r]+=len[r]*w;
    }
    void mdfy(int l,int r,int cr,int p,ll w)//ll
    {
      if(l==r){sum[cr]+=w;return;}
      pshd(cr);//!
      int mid=((l+r)>>1);
      if(p<=mid)mdfy(l,mid,ls[cr],p,w);
      else mdfy(mid+1,r,rs[cr],p,w);
      pshp(cr);
    }
    void mdfy(int l,int r,int cr,int L,int R,ll w)//
    {
      if(l>=L&&r<=R){sum[cr]+=len[cr]*w;lazy[cr]+=w;return;}
      pshd(cr);
      int mid=((l+r)>>1);
      if(mid>=L)mdfy(l,mid,ls[cr],L,R,w);
      if(mid<R)mdfy(mid+1,r,rs[cr],L,R,w);
      pshp(cr);
    }
    ll query(int l,int r,int cr,int L,int R)
    {
      if(l>=L&&r<=R)return sum[cr];
      pshd(cr);
      int mid=((l+r)>>1);ll ret=0;
      if(mid>=L)ret+=query(l,mid,ls[cr],L,R);
      if(mid<R)ret+=query(mid+1,r,rs[cr],L,R);
      return ret;
    }
    ll query(int x)
    {
      ll ret=0;
      while(x)
        {
          ret+=query(1,n,1,dfn[top[x]],dfn[x]);
          x=fa[top[x]];
        }
      return ret;
    }
    int main()
    {
      scanf("%d%d",&n,&m);int x,y;
      for(int i=1;i<=n;i++)scanf("%lld",&val[i]);
      for(int i=1;i<n;i++)
        {
          scanf("%d%d",&x,&y);add(x,y);
        }
      dfs1(1);top[1]=1;dfs2(1);
      tim=1;build(1,n,1);
      int op;ll w;
      for(int i=1;i<=m;i++)
        {
          scanf("%d%d",&op,&x);if(op!=3)scanf("%lld",&w);
          if(op==1)mdfy(1,n,1,dfn[x],w);
          if(op==2)mdfy(1,n,1,dfn[x],cq[x],w);
          if(op==3)printf("%lld
    ",query(x));
        }
      return 0;
    }
  • 相关阅读:
    【Android进阶】关于PagerAdapter的使用方法的总结
    不容易系列之(4)——考新郎
    阿牛的EOF牛肉串
    Number Sequence
    盐水的故事
    Digital Roots
    密码 hdu
    不容易系列之(3)—— LELE的RPG难题
    冒泡排序----java实现
    不容易系列之一
  • 原文地址:https://www.cnblogs.com/Narh/p/9296439.html
Copyright © 2011-2022 走看看