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

输入

第一行一个整数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.

输出

对于每一个事件类型为Q的事件,输出一行一个整数,表示此次实验的收集器最终能量。

输入示例


Q
F
Q
C
Q

输出示例


数据规模及约定

n<=100000,m<=300000,1<di,xi<=n,wi,qi<=100000.保证操作合法。

题解

这题的妙点在于 dfs 序的优美,注意这题要的是把每个点拆成入栈时刻和出栈时刻两个点,设节点 i 的入栈时刻为 dli,出栈时刻为 dri,点权为 val[i],那么设 v[dli] = val[i],v[dri] = -val[i],同时记一个标记 s,s[dli] = 1, s[dri] = -1。现在考虑不带换父亲操作,点 i 到根节点的距离等于 Σv[j] (1 ≤ j ≤ dli);修改某子树权值可以视为序列上的区间修改,假设要修改子树 i,则将区间 [dli, dri] 打上懒标记 addv,下传标记的时候该区间维护的权值和加上 Σs[j] (dli ≤ j ≤ dri) * addv 即可,正确性留给读者证(y)明(y)。

上面的东西可以用线段树维护。至于加上了换父亲(C)操作,就可以用 splay 来搞,C操作显然是将一段区间移位,那么可以通过一系列伸展树的分裂、合并操作完成(详细地说就是将指定区间分离出来,再插入到目标位置里,再详细一点请参见代码)。F操作可以将指定区间分离出来,打一个懒标记,再合并成原序列。splay 的标记下传规则跟线段树的一样。

能写出代码,这题就能 AC 了= =。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 100010
#define maxm 200010
#define LL long long
int n; int m, head[maxn], next[maxm], to[maxm];
int clo, val[maxn], dl[maxn], dr[maxn], ids[maxn<<1], dv[maxn<<1], ds[maxn<<1];
void AddEdge(int a, int b) {
to[++m] = b; next[m] = head[a]; head[a] = m;
swap(a, b);
to[++m] = b; next[m] = head[a]; head[a] = m;
return ;
}
void build(int u, int fa) {
dl[u] = ++clo; dv[clo] = val[u]; ds[clo] = 1;
for(int e = head[u]; e; e = next[e]) if(to[e] != fa) build(to[e], u);
dr[u] = ++clo; dv[clo] = -val[u]; ds[clo] = -1;
return ;
} struct Node {
int sym, sums;
LL val, sumv, addv;
Node() { val = sumv = addv = sym = sums = 0; }
void clear() { val = sumv = addv = sym = sums = 0; return ; }
} nodes[maxn<<1];
int ToT, root, ch[maxn<<1][2], fa[maxn<<1];
void maintain(int u) {
nodes[0].clear();
Node &o = nodes[u], &l = nodes[ch[u][0]], &r = nodes[ch[u][1]];
o.sums = l.sums + o.sym + r.sums;
o.sumv = l.addv * l.sums + l.sumv + o.val + r.addv * r.sums + r.sumv;
return ;
}
void builds(int& u, int pa, int L, int R) {
if(L > R){ u = 0; return ; }
int M = L + R >> 1;
Node& o = nodes[u = ++ToT];
o.sym = o.sums = ds[M];
o.val = o.sumv = dv[M]; o.addv = 0;
ids[M] = u; fa[u] = pa;
builds(ch[u][0], u, L, M - 1); builds(ch[u][1], u, M + 1, R);
maintain(u);
return ;
}
void pushdown(int u) {
Node &o = nodes[u], &l = nodes[ch[u][0]], &r = nodes[ch[u][1]];
if(o.addv) {
// printf("%lld ", o.sumv);
o.sumv += o.addv * o.sums; o.val += o.addv * o.sym;
l.addv += o.addv; r.addv += o.addv;
// printf("pushdown: (u)%d (o.addv)%lld (o.sumv)%lld\n", u, o.addv, o.sumv);
o.addv = 0;
}
nodes[0].clear();
return ;
}
void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(ch[y][1] == u) swap(l, r);
if(z) ch[z][ch[z][1]==y] = u;
fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
ch[y][l] = ch[u][r]; ch[u][r] = y;
maintain(y); maintain(u);
return ;
}
int St[maxn], top;
void splay(int u) {
int t = u;
while(fa[t]) St[++top] = t, t = fa[t];
St[++top] = t;
while(top) pushdown(St[top--]);
while(fa[u]) {
int y = fa[u], z = fa[y];
if(!z) rotate(u);
else {
if((ch[z][0] == y) ^ (ch[y][0] == u)) rotate(u);
else rotate(y);
rotate(u);
}
}
return ;
}
int splitl(int u) {
splay(u);
int ret = ch[u][0];
Node &o = nodes[u], &l = nodes[ch[u][0]];
nodes[0].clear();
o.sumv -= (l.sumv + l.addv * l.sums);
fa[ret] = 0; ch[u][0] = 0;
return ret;
}
int splitr(int u) {
splay(u);
int ret = ch[u][1];
Node &o = nodes[u], &r = nodes[ch[u][1]];
nodes[0].clear();
o.sumv -= (r.sumv + r.addv * r.sums);
fa[ret] = 0; ch[u][1] = 0;
return ret;
}
void update(int u, int v) {
splay(u);
nodes[u].addv += v;
return ;
}
void merge(int a, int b) {
if(!a || !b) return ;
while(ch[a][1]) a = ch[a][1];
while(ch[b][0]) b = ch[b][0];
splay(a); splay(b);
Node &o = nodes[b], &l = nodes[a];
o.sumv += (l.sumv + l.addv * l.sums);
fa[a] = b; ch[b][0] = a;
return ;
} int main() {
n = read();
for(int i = 2; i <= n; i++) AddEdge(i, read());
for(int i = 1; i <= n; i++) val[i] = read(); build(1, 0);
builds(root, 0, 1, n << 1);
int q = read();
while(q--) {
char tp = Getchar();
while(!isalpha(tp)) tp = Getchar();
if(tp == 'Q') {
int x = dl[read()];
splay(ids[x]);
Node& o = nodes[ids[x]], &r = nodes[ch[ids[x]][1]];
LL ans = o.sumv + o.addv * o.sums - r.sumv - r.addv * r.sums;
printf("%lld\n", ans);
}
if(tp == 'F') {
int x = read(), v = read(), xl = dl[x], xr = dr[x], lt = 0, rt = 0;
lt = splitl(ids[xl]);
rt = splitr(ids[xr]);
update(ids[xl], v);
merge(lt, ids[xl]);
merge(ids[xr], rt);
}
if(tp == 'C') {
int x = read(), fax = read(), xl = dl[x], xr = dr[x], lt, rt;
lt = splitl(ids[xl]);
rt = splitr(ids[xr]);
merge(lt, rt);
rt = splitr(ids[dl[fax]]);
lt = ids[dl[fax]];
merge(lt, ids[xl]);
merge(ids[xr], rt);
}
} return 0;
}

不知为何慢的飞起,会不会是因为我用的数组版 splay?求帮忙优化orz。

[BZOJ3786]星系探索的更多相关文章

  1. BZOJ3786 星系探索 【Splay维护dfs序】*

    BZOJ3786 星系探索 Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均 ...

  2. [BZOJ3786]星系探索(伪ETT)

    3786: 星系探索 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1638  Solved: 506[Submit][Status][Discuss ...

  3. [BZOJ3786] 星系探索(括号序列+Splay)

    3786: 星系探索 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 2191  Solved: 644[Submit][Status][Discuss ...

  4. bzoj3786星系探索 splay

    3786: 星系探索 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1314  Solved: 425[Submit][Status][Discuss ...

  5. BZOJ3786星系探索——非旋转treap(平衡树动态维护dfs序)

    题目描述 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球没有依赖星球. ...

  6. BZOJ3786:星系探索(Splay,括号序)

    Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球 ...

  7. bzoj3786星系探索(splay维护dfs序)

    Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球 ...

  8. BZOJ3786: 星系探索 Splay+DFS序

    题目大意:给你一个树,支持三种操作,子树加,点到根的路径和,改变某一个点的父亲. 分析: 看起来像一个大LCT,但是很显然,LCT做子树加我不太会啊... 那么,考虑更换一个点的父亲这个操作很有意思, ...

  9. BZOJ3786: 星系探索(伪ETT)

    题面 传送门 题解 坑啊--我好像把\(Splay\)的东西全忘光了-- \(ETT\)(\(Euler\ Tour\ Tree\))是一种可以资瓷比\(LCT\)更多功能的数据结构,然而不管是功能还 ...

随机推荐

  1. JavaScript和html5 canvas生成圆形印章

    代码: function createSeal(id,company,name){ var canvas = document.getElementById(id); var context = ca ...

  2. [AaronYang]C#人爱学不学[2]

    1. 记事本写C#,脱离vs 新建记事本,名字为 helloworld.cs using System; namespace Hello{ public class HelloWorldSay{ st ...

  3. javascript继承(六)—实现多继承

    在上一篇javascript继承—prototype最优两种继承(空函数和循环拷贝)(3) ,介绍了js较完美继承的两种实现方案,那么下面来探讨一下js里是否有多继承,如何实现多继承.在这里可以看看j ...

  4. 每天一个linux命令(54):sftp命令

    sftp 是一个交互式文件传输程式.它类似于 ftp, 但它进行加密传输,比FTP有更高的安全性.下边就简单介绍一下如何远程连接主机,进行文件的上传和下载,以及一些相关操作. 举例,如远程主机的 IP ...

  5. Solr -- 实时搜索

    在solr中,实时搜索有3种方案 ①soft commit,这其实是近实时搜索,不能完全实时. ②RealTimeGet,这是实时,但只支持根据文档ID的查询. ③和第一种类似,只是触发softcom ...

  6. Fedora21下安装cuda7.5

    Fedora21装cuda7.5 首先制作启动U盘.装好fedora21后别做任何update等yum和rpm操作,按照下面步骤走. 其中遇到用UEFI模式安装cuda时,系统一定要求提供公钥和私钥, ...

  7. MVC传值汇总

     方法一: Url传参是通过Get的方式,一般我们都是通过一定规则的Url来传参.比如下面的URL. http://localhost/contorller/action/?Params1=a& ...

  8. Vijos1889 天真的因数分解

    描述 小岛: 什么叫做因数分解呢?doc : 就是将给定的正整数n, 分解为若干个素数连乘的形式.小岛: 那比如说 n=12 呢?doc : 那么就是 12 = 2 X 2 X 3 呀.小岛: 呜呜, ...

  9. iOS应用开发最佳实践系列一:编写高质量的Objective-C代码

          本文由海水的味道编译整理,转载请注明译者和出处,请勿用于商业用途! 点标记语法 属性和幂等方法(多次调用和一次调用返回的结果相同)使用点标记语法访问,其他的情况使用方括号标记语法. 良好的 ...

  10. iBatisnet系列(二) 配置运行环境和日志处理

    http://hjf1223.cnblogs.com/archive/2006/04/24/383119.aspx 刚爬完鼓山回来,想到这篇刚刚开始,不敢怠慢,洗完澡休息一下就到电脑旁边来了.现在我开 ...