BZOJ 3786: 星系探索

18 篇文章 0 订阅
13 篇文章 0 订阅

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

Solution

本题非常卡常数,一开始直接扒3153的代码狂T不止,改写Splay后也是狂T不止,最后把Splay从数组储存改成结构体储存才AC。                                                 ———Claris

涨姿势题。。
用Splay维护一个dfs序,这个dfs序是那种进入也算,出去也算的dfs序
然后进入的算负的,出去的算正的,这样可以保证对于一个点正dfs序到根的正dfs序之间数字的和恰好是那条路径的权值(不是路径上的要不不出现在这段dfs序中,要不出现了2次,一次正一次负恰好抵消对答案无影响)。
然后就是Splay的板子啦

Code

这是那个结构体版的

/**************************************************************
    Problem: 3786
    User: bblss123
    Language: C++
    Result: Accepted
    Time:23772 ms
    Memory:14004 kb
****************************************************************/

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<time.h>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef double db;
typedef unsigned ud;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;

#define fi first 
#define se second
#define pb push_back
#define ph push
#define showtime fprintf(stderr,"time = %.15f\n",clock() / (double)CLOCKS_PER_SEC)

const int INF=(ud)-1>>1;
const ll inf=(ull)-1>>1;

template<class T>void rd(T &a){
    a=0;char c;
    while(c=getchar(),c<48);
    do a=a*10+(c^48);
        while(c=getchar(),c>47);
}
inline void rdc(char &c){
    c=0;char s;
    while(s=getchar(),s<65);
    c=s;
}
template<class T>void nt(T x){
    if(!x)return;
    nt(x/10);
    putchar(48+x%10);
}
template<class T>void pt(T x){
    if(!x)putchar('0');
    else nt(x);
}
template<class T>void Max(T &a,T b){
    if(a<b)a=b;
}
template<class T>void Min(T &a,T b){
    if(a==-1||a>b)a=b;
}
const int M=2e5+10;
const int N=1e5+2;
int f[N],w[N];
struct Edge{
    int to,nxt;
}G[N];
int tot_edge,head[N];
inline void add_edge(int from,int to){
    G[tot_edge]=(Edge){to,head[from]};
    head[from]=tot_edge++;
}
struct Splay_Tree{
    struct node{
        int tr[2],fa,sz,pos;
        ll sum,add,val;
        inline node(){
            tr[0]=tr[1]=sum=add=val=fa=sz=pos=0;
        }
    }T[M];
    int que[M],allc,rt;
    inline void up(int &x){
        node &l=T[T[x].tr[0]],&r=T[T[x].tr[1]];
        T[x].sz=l.sz+r.sz+1;
        T[x].sum=l.sum+r.sum+T[x].val;
        T[x].pos=l.pos+r.pos+(x<=N);
    }
    inline void down(int &x){
        if(!T[x].add)return;
        ll &ad=T[x].add;
        T[x].val+=x>=N?-ad:ad;
        node &l=T[T[x].tr[0]],&r=T[T[x].tr[1]];
        l.add+=T[x].add,r.add+=T[x].add;
        int nagl=l.sz-l.pos,nagr=r.sz-r.pos;
        l.sum+=1ll*l.pos*ad-1ll*nagl*ad;
        r.sum+=1ll*r.pos*ad-1ll*nagr*ad;
        ad=0;
    }
    inline void rotate(int x,int &k){
        int y=T[x].fa,z=T[y].fa,r=T[y].tr[0]==x,l=r^1;
        if(y==k)k=x;
        else{
            if(T[z].tr[0]==y)T[z].tr[0]=x;
            else T[z].tr[1]=x;
        }
        T[x].fa=z,T[y].fa=x,T[T[x].tr[r]].fa=y;
        T[y].tr[l]=T[x].tr[r],T[x].tr[r]=y;
        up(y);
    }
    inline void Splay(int x,int &k){
        for(int v=x;v!=rt;v=T[v].fa)que[++allc]=v;
        que[++allc]=rt;
        for(;allc;)down(que[allc--]);
        for(;x!=k;){
            int y=T[x].fa,z=T[y].fa;
            if(y!=k){
                if(T[z].tr[0]==y^T[y].tr[0]==x)rotate(x,k);
                else rotate(y,k);
            }
            rotate(x,k);
        }
        up(x);
    }
    inline void Insert(int x,int w){
        T[x].val=w;
        if(!rt)rt=x;
        else T[rt].tr[1]=x,T[x].fa=rt,up(x),Splay(x,rt);
    }
    inline ll query(int &x){
        Splay(x,rt);
        return T[T[x].tr[0]].sum+T[x].val;
    }
    inline int search(int x,const bool &dir){
        if(!T[x].tr[dir])return x;
        return search(T[x].tr[dir],dir);
    }
    inline void Change(int x,int y){//turn x's father to y
        Splay(x,rt);
        int k1=search(T[rt].tr[0],1);
        Splay(x+N,rt);
        int k2=search(T[rt].tr[1],0);
        Splay(k1,rt),Splay(k2,T[rt].tr[1]);
        int w=T[k2].tr[0];
        T[k2].tr[0]=0,T[w].fa=0;
        Splay(y,rt);
        int k=search(T[y].tr[1],0);
        Splay(k,T[y].tr[1]);
        T[w].fa=k,T[k].tr[0]=w;
    }
    inline void Add(int x,int w){
        Splay(x,rt);
        int k1=search(T[rt].tr[0],1);
        Splay(x+N,rt);
        int k2=search(T[rt].tr[1],0);
        Splay(k1,rt),Splay(k2,T[rt].tr[1]);
        int s=T[k2].tr[0];
        T[s].add+=w,T[s].sum+=1ll*w*T[s].pos-1ll*(T[s].sz-T[s].pos)*w;
    }
}spt;
int dfs_clock;
inline void dfs(int v){
    spt.Insert(v+1,w[v]);
    for(int i=head[v];~i;i=G[i].nxt)
        dfs(G[i].to);
    spt.Insert(v+N+1,-w[v]);
}
int main(){
    int n,q,u,v;cin>>n;
    memset(head,-1,sizeof(head));
    tot_edge=0;
    for(int i=2;i<=n;++i)
        rd(f[i]),add_edge(f[i],i);
    for(int i=1;i<=n;++i)rd(w[i]);
    spt.Insert(1,0);
    dfs(1);
    spt.Insert(N<<1|1,0);
    char c;
    for(cin>>q;q--;){
        rdc(c);
        switch(c){
            case('Q'):
                rd(v),++v;
                pt(spt.query(v)),putchar('\n');
                break;
            case('C')://turn u's father to v
                rd(u),rd(v),++u,++v;
                spt.Change(u,v);
                break;
            case('F'):
                rd(u),rd(v);++u;
                spt.Add(u,v);
                break;
        }
    }
    return 0;
}


还有数组版。。

/**************************************************************
    Problem: 3786
    User: bblss123
    Language: C++
    Result: Time_Limit_Exceed
****************************************************************/

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<time.h>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef double db;
typedef unsigned ud;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;

#define fi first 
#define se second
#define pb push_back
#define ph push
#define showtime fprintf(stderr,"time = %.15f\n",clock() / (double)CLOCKS_PER_SEC)

const int INF=(ud)-1>>1;
const ll inf=(ull)-1>>1;

template<class T>void rd(T &a){
    a=0;char c;
    while(c=getchar(),c<48);
    do a=a*10+(c^48);
        while(c=getchar(),c>47);
}
inline void rdc(char &c){
    c=0;char s;
    while(s=getchar(),s<65);
    c=s;
}
template<class T>void nt(T x){
    if(!x)return;
    nt(x/10);
    putchar(48+x%10);
}
template<class T>void pt(T x){
    if(!x)putchar('0');
    else nt(x);
}
template<class T>void Max(T &a,T b){
    if(a<b)a=b;
}
template<class T>void Min(T &a,T b){
    if(a==-1||a>b)a=b;
}
const int M=2e5+10;
const int N=1e5+2;
int f[N],w[N];
struct Edge{
    int to,nxt;
}G[N];
int tot_edge,head[N];
inline void add_edge(int from,int to){
    G[tot_edge]=(Edge){to,head[from]};
    head[from]=tot_edge++;
}
struct Splay_Tree{
    int tr[M][2],rt,fa[M],que[M],sz[M],allc,pos[M];
    ll sum[M],add[M],val[M];
    inline void up(int &x){
        sz[x]=sz[tr[x][0]]+sz[tr[x][1]]+1;
        sum[x]=sum[tr[x][0]]+sum[tr[x][1]]+val[x];
        pos[x]=pos[tr[x][0]]+pos[tr[x][1]]+(x<=N);
    }
    inline void down(int &x){
        if(!add[x])return;
        val[x]+=x>=N?-add[x]:add[x];
        int l=tr[x][0],r=tr[x][1];
        add[l]+=add[x],add[r]+=add[x];
        int nagl=sz[l]-pos[l],nagr=sz[r]-pos[r];
        sum[tr[x][0]]+=1ll*pos[l]*add[x]-1ll*nagl*add[x];
        sum[tr[x][1]]+=1ll*pos[r]*add[x]-1ll*nagr*add[x];
        add[x]=0;
    }
    inline void rotate(int x,int &k){
        int y=fa[x],z=fa[y],r=tr[y][0]==x,l=r^1;
        if(y==k)k=x;
        else{
            if(tr[z][0]==y)tr[z][0]=x;
            else tr[z][1]=x;
        }
        fa[x]=z,fa[y]=x,fa[tr[x][r]]=y;
        tr[y][l]=tr[x][r],tr[x][r]=y;
        up(y);
    }
    inline void Splay(int x,int &k){
        for(int v=x;v!=rt;v=fa[v])que[++allc]=v;
        que[++allc]=rt;
        for(;allc;)down(que[allc--]);
        for(;x!=k;){
            int y=fa[x],z=fa[y];
            if(y!=k){
                if(tr[z][0]==y^tr[y][0]==x)rotate(x,k);
                else rotate(y,k);
            }
            rotate(x,k);
        }
        up(x);
    }
    inline void Insert(int x,int w){
        val[x]=w;
        if(!rt)rt=x;
        else tr[rt][1]=x,fa[x]=rt,up(x),Splay(x,rt);
    }
    inline ll query(int &x){
        Splay(x,rt);
        return sum[tr[x][0]]+val[x];
    }
    inline int search(int x,const bool &dir){
        if(!tr[x][dir])return x;
        return search(tr[x][dir],dir);
    }
    inline void Change(int x,int y){//turn x's father to y
        Splay(x,rt);
        int k1=search(tr[rt][0],1);
        Splay(x+N,rt);
        int k2=search(tr[rt][1],0);
        Splay(k1,rt),Splay(k2,tr[rt][1]);
        int w=tr[k2][0];
        tr[k2][0]=0,fa[w]=0;
        Splay(y,rt);
        int k=search(tr[y][1],0);
        Splay(k,tr[y][1]);
        fa[w]=k,tr[k][0]=w;
    }
    inline void Add(int x,int w){
        Splay(x,rt);
        int k1=search(tr[rt][0],1);
        Splay(x+N,rt);
        int k2=search(tr[rt][1],0);
        Splay(k1,rt),Splay(k2,tr[rt][1]);
        int s=tr[k2][0];
        add[s]+=w,sum[s]+=1ll*w*pos[s]-1ll*(sz[s]-pos[s])*w;
    }
}spt;
int dfs_clock;
inline void dfs(int v){
    spt.Insert(v+1,w[v]);
    for(int i=head[v];~i;i=G[i].nxt)
        dfs(G[i].to);
    spt.Insert(v+N+1,-w[v]);
}
int main(){
    int n,q,u,v;cin>>n;
    memset(head,-1,sizeof(head));
    tot_edge=0;
    for(int i=2;i<=n;++i)
        rd(f[i]),add_edge(f[i],i);
    for(int i=1;i<=n;++i)rd(w[i]);
    spt.Insert(1,0);
    dfs(1);
    spt.Insert(N<<1|1,0);
    char c;
    for(cin>>q;q--;){
        rdc(c);
        switch(c){
            case('Q'):
                rd(v),++v;
                pt(spt.query(v)),putchar('\n');
                break;
            case('C')://turn u's father to v
                rd(u),rd(v),++u,++v;
                spt.Change(u,v);
                break;
            case('F'):
                rd(u),rd(v);++u;
                spt.Add(u,v);
                break;
        }
    }
    return 0;
}

卡常数又到了一个新境界

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值