[bzoj3786][splay]星系探索

6 篇文章 0 订阅

3786: 星系探索

Time Limit: 40 Sec Memory Limit: 256 MB
Submit: 1524 Solved: 484
[Submit][Status][Discuss]
Description

物理学家小C的研究正遇到某个瓶颈。

他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球。主星球没有依赖星球。

我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关系具有传递性,即若星球a依赖星球b,星球b依赖星球c,则有星球a依赖星球c.

对于这个神秘的星系中,小C初步探究了它的性质,发现星球之间的依赖关系是无环的。并且从星球a出发只能直接到达它的依赖星球b.

每个星球i都有一个能量系数wi.小C想进行若干次实验,第i次实验,他将从飞船上向星球di发射一个初始能量为0的能量收集器,能量收集器会从星球di开始前往主星球,并收集沿途每个星球的部分能量,收集能量的多少等于这个星球的能量系数。

但是星系的构成并不是一成不变的,某些时刻,星系可能由于某些复杂的原因发生变化。

有些时刻,某个星球能量激发,将使得所有依赖于它的星球以及他自己的能量系数均增加一个定值。还有可能在某些时刻,某个星球的依赖星球会发生变化,但变化后依然满足依赖关系是无环的。

现在小C已经测定了时刻0时每个星球的能量系数,以及每个星球(除了主星球之外)的依赖星球。接下来的m个时刻,每个时刻都会发生一些事件。其中小C可能会进行若干次实验,对于他的每一次实验,请你告诉他这一次实验能量收集器的最终能量是多少。

Input

第一行一个整数n,表示星系的星球数。

接下来n-1行每行一个整数,分别表示星球2-n的依赖星球编号。

接下来一行n个整数,表示每个星球在时刻0时的初始能量系数wi.

接下来一行一个整数m,表示事件的总数。

事件分为以下三种类型。

(1)”Q di”表示小C要开始一次实验,收集器的初始位置在星球di.

(2)”C xi yi”表示星球xi的依赖星球变为了星球yi.

(3)”F pi qi”表示星球pi能量激发,常数为qi.

Output

对于每一个事件类型为Q的事件,输出一行一个整数,表示此次实验的收集器最终能量。

Sample Input

3

1

1

4 5 7

5

Q 2

F 1 3

Q 2

C 2 3

Q 2

Sample Output

9

15

25
HINT

n<=100000,m<=300000,1

sol:

这题卡常数,请尽量手动updata

由于要对子树修改,所以不能lct了。因为这题并不会出现森林,我们考虑使用splay维护dfs序,点进栈时设为1,退栈时设为-1,那么他到根的前缀和就是他到根的路径和。这题只要维护子树和和子树系数和就好了。
思考一下这题的加强版,如果询问的是任意 u,v路径的权值和的话怎么做。
可以用u到根的权值和+v到根的-lca到根-fa[lca]到根的
那么问题就变成了怎么求lca了。
用lct维护一下树的形态,然后用access求lca即可。其余代码不变。

T的代码

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long ll;
int n,m;

inline int read()
{
    char c;
    bool pd=0;
    while((c=getchar())>'9'||c<'0')
    if(c=='-') pd=1;
    int res=c-'0';
    while((c=getchar())>='0'&&c<='9')
    res=(res<<3)+(res<<1)+c-'0';
    return pd?-res:res;
}
const int N=210000;
int lc[N],rc[N],fa[N],mul[N],muls[N],tag[N],val[N];
ll sum[N];
inline void updata(const int &x)
{
    muls[x]=muls[lc[x]]+muls[rc[x]]+mul[x];
    sum[x]=val[x]+sum[lc[x]]+sum[rc[x]];
}
inline void tag_add(const int &x,const int &y)
{
    if(!x) return;
    sum[x]+=(ll)muls[x]*y;
    val[x]+=mul[x]>0?y:-y;
    tag[x]+=y;
}
inline void tag_down(const int &x)
{
    if(tag[x])
    {
        tag_add(lc[x],tag[x]);
        tag_add(rc[x],tag[x]);
        tag[x]=0;
    }
}
inline void rotate(const int &x)
{
    int y=fa[x],z=fa[y];
    int b=lc[y]==x?rc[x]:lc[x];
    if(b) fa[b]=y;
    fa[y]=x;fa[x]=z;
    if(z)
    {
        if(lc[z]==y) lc[z]=x;
        else rc[z]=x;
    }
    if(lc[y]==x) lc[y]=b,rc[x]=y;
    else rc[y]=b,lc[x]=y;
    updata(y);
}
int sta[N],rt;
inline void simplex(const int &x,const int &f)
{
    if(x!=f) simplex(fa[x],f);
    tag_down(x);
}
inline void splay(int x,const int &f)
{
    sta[sta[0]=1]=x;
    for(int y=x;y!=f;y=fa[y]) sta[++sta[0]]=fa[y];
    while(sta[0]) tag_down(sta[sta[0]--]);
//  simplex(x,f);
    while(fa[x]!=f)
    {
        if(fa[fa[x]]!=f)
        {
            if((lc[fa[fa[x]]]==fa[x])==(lc[fa[x]]==x)) rotate(fa[x]);
            else rotate(x);
        }
        rotate(x);
    }
    updata(x);
    if(!fa[x]) rt=x;
}
int tot,fir[N],nex[N],go[N];
inline void add(const int &x,const int &y)
{
    nex[++tot]=fir[x];fir[x]=tot;go[tot]=y;
    nex[++tot]=fir[y];fir[y]=tot;go[tot]=x;
}
int q[N];
inline void dfs(const int &u,const int &f)
{
    q[++q[0]]=2*u-1;
    int e,v;
    for(e=fir[u];v=go[e],e;e=nex[e])
    if(v!=f) dfs(v,u);
    q[++q[0]]=2*u;
}
inline void build(int &k,const int &l,const int &r)
{
    if(l>r) return;
    int mid=l+r>>1;
    k=q[mid];
    build(lc[k],l,mid-1);
    build(rc[k],mid+1,r);
    if(lc[k]) fa[lc[k]]=k;
    if(rc[k]) fa[rc[k]]=k;
    updata(k);
}
char sr[5];
inline int find_nex(const int &x)
{
    splay(x,0);
    int y=rc[x];
    while(lc[y]) y=lc[y];
    return y;
}
inline int find_pre(const int &x)
{
    splay(x,0);
    int y=lc[x];
    while(rc[y]) y=rc[y];
    return y;
}
int main()
{
//  freopen("3786.in","r",stdin);
//  freopen(".out","w",stdout);
    srand(19260817);
    n=read();
    for(int i=2;i<=n;++i) add(read(),i);
    q[++q[0]]=2*n+1;
    dfs(1,0);
    q[++q[0]]=2*n+2;
    for(int i=1;i<=n;++i) mul[(i<<1)-1]=1,mul[i<<1]=-1;
    for(int i=1;i<=n;++i)
    {
        val[(i<<1)-1]=val[i<<1]=read();
        val[i<<1]*=-1;
    }
    build(rt,1,q[0]);
    m=read();
    int x,y,z,l,r;
    while(m--)
    {
        scanf("%s",sr+1);
        x=read();
//      splay((rand()%(2*n+2))+1,0);
        if(sr[1]=='Q')
        {
            r=find_nex((x<<1)-1);
            splay(r,0);
            printf("%lld\n",sum[lc[r]]);
        }
        if(sr[1]=='C')
        {
            y=read();
            l=find_pre((x<<1)-1);
            r=find_nex(x<<1);
            splay(l,0);
            splay(r,l);
            z=lc[r];
            lc[r]=0;
            splay(r,0);
            r=find_nex((y<<1)-1);
//          splay((y<<1)-1,0);
            splay(r,(y<<1)-1);
            lc[r]=z;
            fa[z]=r;
            splay(z,0);
        }
        if(sr[1]=='F')
        {
            y=read();
            l=find_pre((x<<1)-1);
            r=find_nex(x<<1);
            splay(l,0);
            splay(r,l);
            tag_add(lc[r],y);
            splay(lc[r],0);
        }
    }
}

手动updata版本

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long ll;
int n,m;

inline int read()
{
    char c;
    bool pd=0;
    while((c=getchar())>'9'||c<'0')
    if(c=='-') pd=1;
    int res=c-'0';
    while((c=getchar())>='0'&&c<='9')
    res=(res<<3)+(res<<1)+c-'0';
    return pd?-res:res;
}
const int N=210000;
int lc[N],rc[N],fa[N],mul[N],muls[N],tag[N],val[N];
ll sum[N];
inline void updata(const int &x)
{
    muls[x]=muls[lc[x]]+muls[rc[x]]+mul[x];
    sum[x]=val[x]+sum[lc[x]]+sum[rc[x]];
}
inline void tag_add(const int &x,const int &y)
{
    if(!x) return;
    sum[x]+=(ll)muls[x]*y;
    val[x]+=mul[x]>0?y:-y;
    tag[x]+=y;
}
inline void tag_down(const int &x)
{
    if(tag[x])
    {
        tag_add(lc[x],tag[x]);
        tag_add(rc[x],tag[x]);
        tag[x]=0;
    }
}
inline void rotate(const int &x)
{
    int y=fa[x],z=fa[y];
    int b=lc[y]==x?rc[x]:lc[x];
    if(b) fa[b]=y;
    fa[y]=x;fa[x]=z;
    if(z)
    {
        if(lc[z]==y) lc[z]=x;
        else rc[z]=x;
    }
    if(lc[y]==x) lc[y]=b,rc[x]=y;
    else rc[y]=b,lc[x]=y;
    updata(y);
}
int sta[N],rt;
inline void simplex(const int &x,const int &f)
{
    if(x!=f) simplex(fa[x],f);
    tag_down(x);
}
inline void splay(int x,const int &f)
{
    sta[sta[0]=1]=x;
    for(int y=x;y!=f;y=fa[y]) sta[++sta[0]]=fa[y];
    while(sta[0]) tag_down(sta[sta[0]--]);
//  simplex(x,f);
    while(fa[x]!=f)
    {
        if(fa[fa[x]]!=f)
        {
            if((lc[fa[fa[x]]]==fa[x])==(lc[fa[x]]==x)) rotate(fa[x]);
            else rotate(x);
        }
        rotate(x);
    }
    updata(x);
    if(!fa[x]) rt=x;
}
int tot,fir[N],nex[N],go[N];
inline void add(const int &x,const int &y)
{
    nex[++tot]=fir[x];fir[x]=tot;go[tot]=y;
    nex[++tot]=fir[y];fir[y]=tot;go[tot]=x;
}
int q[N];
inline void dfs(const int &u,const int &f)
{
    q[++q[0]]=2*u-1;
    int e,v;
    for(e=fir[u];v=go[e],e;e=nex[e])
    if(v!=f) dfs(v,u);
    q[++q[0]]=2*u;
}
inline void build(int &k,const int &l,const int &r)
{
    if(l>r) return;
    int mid=l+r>>1;
    k=q[mid];
    build(lc[k],l,mid-1);
    build(rc[k],mid+1,r);
    if(lc[k]) fa[lc[k]]=k;
    if(rc[k]) fa[rc[k]]=k;
    updata(k);
}
char sr[5];
inline int find_nex(const int &x)
{
    splay(x,0);
    int y=rc[x];
    while(lc[y]) y=lc[y];
    return y;
}
inline int find_pre(const int &x)
{
    splay(x,0);
    int y=lc[x];
    while(rc[y]) y=rc[y];
    return y;
}
int main()
{
//  freopen("3786.in","r",stdin);
//  freopen(".out","w",stdout);
    srand(19260817);
    n=read();
    for(int i=2;i<=n;++i) add(read(),i);
    q[++q[0]]=2*n+1;
    dfs(1,0);
    q[++q[0]]=2*n+2;
    for(int i=1;i<=n;++i) mul[(i<<1)-1]=1,mul[i<<1]=-1;
    for(int i=1;i<=n;++i)
    {
        val[(i<<1)-1]=val[i<<1]=read();
        val[i<<1]*=-1;
    }
    build(rt,1,q[0]);
    m=read();
    int x,y,z,l,r;
    while(m--)
    {
        scanf("%s",sr+1);
        x=read();
        if(sr[1]=='Q')
        {
            r=find_nex((x<<1)-1);
            splay(r,0);
            printf("%lld\n",sum[lc[r]]);
        }
        if(sr[1]=='C')
        {
            y=read();
            l=find_pre((x<<1)-1);
            r=find_nex(x<<1);
            splay(l,0);
            splay(r,l);
            z=lc[r];
            lc[r]=0;
            updata(r);updata(l);
            r=find_nex((y<<1)-1);
            splay(r,(y<<1)-1);
            lc[r]=z;
            fa[z]=r;
            updata(r);
            updata((y<<1)-1);
        }
        if(sr[1]=='F')
        {
            y=read();
            splay((x<<1)-1,0);
            splay(x<<1,(x<<1)-1);
            z=rc[rt];
            val[rt]+=mul[rt]*y;
            val[z]+=mul[z]*y;
            tag_add(lc[z],y);
            updata(z);updata(rt);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值