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; }