bzoj3786 星系探索

题面:

物理学家小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可能会进行若干次实验,对于他的每一次实验,请你告诉他这一次实验能量收集器的最终能量是多少。

学长出的题啊。。。

欧拉序+splay,将每个点按dfs序分成两个点,然后进行:

1.区间求和(splay基础)

2.区间加法(还是splay基础)

3.区间移动(其实就是删除+插入)

需要注意的是区间加法。为了维护前缀和的正确性,标记下推时应程一个系数(1 、-1)。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
#define N 100050
#define ll long long
ll n,m,hed[N],cnt;
struct EDGE
{
    ll to,nxt;
}e[N];
void ae(ll f,ll t)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
struct Splay
{
    ll ch[2],fa,vl,siz,sum,mrk;
    ll kk,sk;
}tr[2*N];
ll tin[N],tout[N],tot=1,a[N],rt;
void dfs(ll u)
{
    tin[u]=++tot;
    tr[tot].vl = a[u];
    tr[tot].kk = 1;
    tr[tot].sk = 1;
    for(ll j=hed[u];j;j=e[j].nxt)dfs(e[j].to);
    tout[u]=++tot;
    tr[tot].vl = -a[u];
    tr[tot].kk = -1;
    tr[tot].sk = -1;
}
void update(ll u)
{
    ll l = tr[u].ch[0],r = tr[u].ch[1];
    tr[u].siz = tr[l].siz+tr[r].siz+1;
    tr[u].sk = tr[l].sk+tr[r].sk+tr[u].kk;
    tr[u].sum = tr[l].sum+tr[r].sum+tr[u].vl;
}
void pushdown(ll x)
{
    ll l = tr[x].ch[0],r = tr[x].ch[1],k = tr[x].mrk;
    if(k)
    {
        if(l)tr[l].vl+=k*tr[l].kk,tr[l].sum+=tr[l].sk*k,tr[l].mrk+=k;
        if(r)tr[r].vl+=k*tr[r].kk,tr[r].sum+=tr[r].sk*k,tr[r].mrk+=k;
        tr[x].mrk=0;
    }
}
void build(ll l,ll r,ll f)
{
    if(l>r)return ;
    ll mid = (l+r)>>1;
    if(l!=r)build(l,mid-1,mid),build(mid+1,r,mid);
    tr[mid].fa = f;
    tr[f].ch[mid>=f] = mid;
    update(mid);
}
void rotate(ll x)
{
    ll y = tr[x].fa,z = tr[y].fa,k = (tr[y].ch[1]==x);
    tr[y].ch[k] = tr[x].ch[k^1],tr[tr[x].ch[k^1]].fa = y;
    tr[x].ch[k^1] = y,tr[y].fa = x;
    tr[z].ch[tr[z].ch[1]==y]=x,tr[x].fa = z;
    update(y),update(x);
}
void splay(ll x,ll goal)
{
    while(tr[x].fa!=goal)
    {
        ll y = tr[x].fa,z = tr[y].fa;
        if(z!=goal)
            ((tr[y].ch[1]==x)^(tr[z].ch[1]==y))?rotate(x):rotate(y);
        rotate(x);
    }
    if(!goal)rt = x;
}
ll get_th(ll x)
{
    ll ret = 0;
    if(x==rt)ret = tr[tr[x].ch[0]].siz+1;
    else if(x==tr[tr[x].fa].ch[0])ret = get_th(tr[x].fa)-1-tr[tr[x].ch[1]].siz;
    else ret = get_th(tr[x].fa)+1+tr[tr[x].ch[0]].siz;
    pushdown(x);
    return ret;
}
ll find_kth(ll x,ll k)
{
    pushdown(x);
    ll t = tr[tr[x].ch[0]].siz;
    if(k<=t)return find_kth(tr[x].ch[0],k);
    else if(k==t+1)return x;
    else return find_kth(tr[x].ch[1],k-1-t);
}
void ccc(ll x,ll y)
{
    ll l,r;
    l = get_th(tin[x])-1,r = get_th(tout[x])+1;
    l = find_kth(rt,l),r = find_kth(rt,r);
    splay(l,0),splay(r,l);
    ll z = tr[tr[rt].ch[1]].ch[0];
    tr[tr[z].fa].ch[0]=0;
    update(tr[z].fa),update(rt);
    l = get_th(tin[y]),r = l+1;
    l = find_kth(rt,l),r = find_kth(rt,r);
    splay(l,0),splay(r,l);
    tr[z].fa = tr[rt].ch[1];
    tr[tr[rt].ch[1]].ch[0] = z;
    update(tr[z].fa),update(rt);
}
void fff(ll x,ll d)
{
    ll l,r;
    l = get_th(tin[x])-1;
    r = get_th(tout[x])+1;
    l = find_kth(rt,l),r = find_kth(rt,r);
    splay(l,0),splay(r,l);
    ll z = tr[r].ch[0];
    tr[z].mrk+=d;
    tr[z].vl+=d*tr[z].kk;
    tr[z].sum+=d*tr[z].sk;
}
int main()
{
    scanf("%lld",&n);
    for(ll f,i=2;i<=n;i++)
    {
        scanf("%lld",&f);
        ae(f,i);
    }
    for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);
    dfs(1);
    build(1,2*n+2,0);
    rt = (2*n+3)>>1;
    scanf("%lld",&m);
    char ch[2];
    ll x,y;
    for(ll i=1;i<=m;i++)
    {
        scanf("%s",ch);
        if(ch[0]=='Q')
        {
            scanf("%lld",&x);
            get_th(tin[x]);
            splay(tin[x],0);
            printf("%lld\n",tr[tr[rt].ch[0]].sum+tr[rt].vl);
        }else if(ch[0]=='C')
        {
            scanf("%lld%lld",&x,&y);
            ccc(x,y);
        }else
        {
            scanf("%lld%lld",&x,&y);
            fff(x,y);
        }
    }
    return 0;
}

 

posted @ 2018-09-09 23:22  LiGuanlin  阅读(112)  评论(0编辑  收藏  举报