DFS序(带入栈出栈标记):

对于一个节点,我们用L[i]和R[i]表示它入栈和出栈的时间。这样[L[i],R[i]]就表示了以i为根的区间。

我们还要将入栈的符号为+,出栈的符号为-,那么令V[i]=sig[i]*val[i]。

这样有什么好处呢?

1.对于一个节点x到根的节点val权值和,等于Sum{V[1,R[x]]}。

2.对于将一个子树所有值+v,等于将[L[i],R[i]]的所有V值+v

这便是一个经典的线段树

但是这样有什么局限性呢?答案必须满足区间加减法(例如这道题DFS序无法求最大值)。

否则怎么做呢?树链剖分!!!!!!!!!!!!!

DFS序好像是Fenwich,树链剖分好像是Splay

-------------------------------------------------------------------------------------------------------

暑假出的题,其实是从一道BZOJ的题摘下来的,原题还有换根操作,只能用splay动态维护DFS序列。

恩先放一个之前写的DFS序列(带入栈出栈标记)+线段树版本的:(写得丑请不要介意)

询问O(logn)修改O(logn)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200010;
int n,m,first[maxn],next[maxn],v[maxn],e;
void AddEdge(int a,int b)
{
     v[++e]=b;
     next[e]=first[a];
     first[a]=e;
}
int F[maxn],L[maxn],s[maxn],val[maxn],tot;
void dfs(int x)
{
     F[x]=++tot; s[tot]=1;
     for(int i=first[x];i;i=next[i]) dfs(v[i]);
     L[x]=++tot; s[tot]=-1;
}
typedef long long LL;
LL sumv[maxn*3],addv[maxn*3],sz[maxn*3];
void maintain(int o,int L,int R)
{
     sumv[o]=0;
     if(L<R) sumv[o]=sumv[o<<1]+sumv[(o<<1)|1];
     sumv[o]+=addv[o]*sz[o];
}
void build(int o,int L,int R)
{
     if(L==R) addv[o]=val[L],sz[o]=s[L];
     else
     {
         int M=L+R>>1,lc=o<<1,rc=lc|1;
         build(lc,L,M); build(rc,M+1,R);
         sz[o]=sz[lc]+sz[rc];
     }
     maintain(o,L,R);
}
int ql,qr,va;
LL query(int o,int L,int R,int add)
{
    if(ql<=L&&R<=qr) return sumv[o]+add*sz[o];
    else
    {
        int M=L+R>>1,lc=o<<1,rc=lc|1;
        LL ans=0;
        if(ql<=M) ans+=query(lc,L,M,add+addv[o]);
        if(qr>M) ans+=query(rc,M+1,R,add+addv[o]);
        return ans;
    }
}
void update(int o,int L,int R)
{
     if(ql<=L&&R<=qr) addv[o]+=va;
     else
     {
        int M=L+R>>1,lc=o<<1,rc=lc|1;
        if(ql<=M) update(lc,L,M);
        if(qr>M) update(rc,M+1,R);
    }
    maintain(o,L,R);
}
int main()
{
    int p;
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&p);
        AddEdge(p,i);
    }
    dfs(1);
    for(int i=1;i<=n;i++) scanf("%d",&p),val[L[i]]=val[F[i]]=p;
    build(1,1,n*2);
    scanf("%d",&m);
    char cmd[4];
    while(m--)
    {
       scanf("%s",cmd);
       if(cmd[0]=='Q')
       {
           scanf("%d",&qr);ql=1;qr=F[qr];
           printf("%lld\n",query(1,1,n*2,0));
       }
       else
       {
           scanf("%d%d",&ql,&va);
           qr=L[ql]; ql=F[ql];
           update(1,1,n*2);
       }
    }
    return 0;
}
View Code

相关文章:

  • 2021-11-23
  • 2021-12-19
  • 2021-07-31
  • 2022-01-07
  • 2021-10-12
  • 2021-06-06
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-01-05
  • 2022-02-11
  • 2021-06-07
  • 2021-09-15
  • 2021-10-24
  • 2022-03-05
  • 2022-12-23
相关资源
相似解决方案