1. 程式人生 > >BZOJ 3786: 星系探索 解題報告

BZOJ 3786: 星系探索 解題報告

void output 是我 表示 一些事 自己 define class cloc

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\n",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 3786: 星系探索 解題報告