zoukankan      html  css  js  c++  java
  • BZOJ 3786: 星系探索 解题报告

    3786: 星系探索

    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的事件,输出一行一个整数,表示此次实验的收集器最终能量。


    第一次见到这么用DFS序的...学习了一下姿势。

    思路:对每个点进去和出来分别维护一个dfs序,然后进去的贡献为正,出来的贡献为负,这样你查询链的时候就可以直接查询出来贡献的左边一个的前缀值,不在链上的肯定差分掉了。

    于是我们发现这个题就是要区间修改,区间移动,前缀查询就可以了。

    区间移动的写splay可能比较方便。


    Code:

    #include <cstdio>
    #define ls ch[now][0]
    #define rs ch[now][1]
    #define fa par[now]
    #define ll long long
    const int N=2e5+10;
    int ch[N][2],par[N],dat[N],exist[N],siz[N],s[N],tot,root;
    ll sum[N],tag[N];
    void updata(int now){sum[now]=sum[ls]+sum[rs]+dat[now],siz[now]=siz[ls]+siz[rs]+exist[now];}
    int identity(int now){return ch[fa][1]==now;}
    void connect(int f,int now,int typ){ch[fa=f][typ]=now;}
    void pushdown(int now)
    {
        if(tag[now])
        {
            sum[ls]+=tag[now]*siz[ls];
            sum[rs]+=tag[now]*siz[rs];
            if(ls) dat[ls]+=tag[now]*exist[ls];
            if(rs) dat[rs]+=tag[now]*exist[rs];
            tag[ls]+=tag[now],tag[rs]+=tag[now];
            tag[now]=0;
        }
    }
    void Rotate(int now)
    {
        int p=fa,typ=identity(now);
        connect(p,ch[now][typ^1],typ);
        connect(par[p],now,identity(p));
        connect(now,p,typ^1);
        updata(p),updata(now);
    }
    void splay(int now,int to)
    {
        to=par[to];
        while(now) s[++tot]=now,now=fa;
        while(tot) pushdown(s[tot--]);
        now=s[1];
        for(;fa!=to;Rotate(now))
            if(par[fa]!=to)
                Rotate(identity(now)^identity(fa)?now:fa);
        if(!to) root=now;
    }
    void query(int now)
    {
        splay(now,root);
        printf("%lld
    ",sum[ls]+dat[now]);
    }
    int pre(int now)
    {
        splay(now,root);
        now=ls;
        while(rs) now=rs;
        return now;
    }
    int suc(int now)
    {
        splay(now,root);
        now=rs;
        while(ls) now=ls;
        return now;
    }
    void modify(int l,int r,ll d)
    {
        l=pre(l),r=suc(r);
        splay(r,root),splay(l,ch[r][0]);
        int now=ch[l][1];
        tag[now]+=d,sum[now]+=d*siz[now],dat[now]+=d*exist[now];
        updata(l),updata(r);
    }
    void change(int l,int r,int to)//把区间[l,r]接到to的右子树
    {
        l=pre(l),r=suc(r);
        splay(r,root),splay(l,ch[r][0]);
        int now=ch[l][1];
        par[now]=ch[l][1]=0;
        updata(l),updata(r);
        int ri=suc(to);
        splay(ri,ch[to][1]);
        connect(ri,now,0);
        updata(ri),updata(to);
    }
    int head[N],to[N<<1],Next[N<<1],cnt;
    void add(int u,int v)
    {
        to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
    }
    int dfn[N],low[N],a[N],f[N],n,m,dfsclock=1;
    void dfs(int now)
    {
        dat[dfn[now]=++dfsclock]=a[now];
        exist[dfsclock]=1;
        for(int v,i=head[now];i;i=Next[i])
            if((v=to[i])!=f[now])
                dfs(v);
        dat[low[now]=++dfsclock]=-a[now];
        exist[dfsclock]=-1;
    }
    void build(int &now,int l,int r)
    {
        if(l>r){now=0;return;}
        now=l+r>>1;
        build(ls,l,now-1),build(rs,now+1,r);
        par[ls]=par[rs]=now;
        updata(now);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=2;i<=n;i++)
            scanf("%d",f+i),add(i,f[i]),add(f[i],i);
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        dfs(1);
        build(root,1,++dfsclock);par[0]=0;
        char op[5];
        scanf("%d",&m);
        for(int d,x,y,i=1;i<=m;i++)
        {
            scanf("%s",op);
            if(op[0]=='Q')
            {
                scanf("%d",&d);
                query(pre(low[d]));
            }
            else if(op[0]=='C')
            {
                scanf("%d%d",&x,&y);
                change(dfn[x],low[x],dfn[y]);
            }
            else
            {
                scanf("%d%d",&x,&y);
                modify(dfn[x],low[x],y);
            }
        }
        return 0;
    }
    

    2018.12.11

  • 相关阅读:
    【BZOJ】2019: [Usaco2009 Nov]找工作(spfa)
    【BZOJ】3668: [Noi2014]起床困难综合症(暴力)
    Redis 字符串结构和常用命令
    Redis实现存取数据+数据存取
    Spring 使用RedisTemplate操作Redis
    使用 java替换web项目的web.xml
    SQL server 从创建数据库到查询数据的简单操作
    SQL server 安装教程
    IntelliJ IDEA 注册码(因为之前的地址被封杀了,所以换了个地址)
    对程序员有帮助的几个非技术实用链接(点我,你不会后悔的)
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10102205.html
Copyright © 2011-2022 走看看