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的事件,输出一行一个整数,表示此次实验的收集器最终能量。

 

Sample Input

3
1
1
4 5 7
5
Q 2
F 1 3
Q 2
C 2 3
Q 2

Sample Output

9
15
25

HINT

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

不得不说这是一道好题,但同时也是一道鬼题。(TMD本机上 27s BZOJ上 TLE ,什么鬼!!!)
dfs序这东西又冒出来了,还升级了,呵呵。。。。这次的dfs序好像叫什么进栈出栈序(好像也叫欧拉序列)吧。
肯定会有许多人想要问dfs序不是只能处理子树信息,不能处理链信息吗?这边是本题最妙的地方——利用欧拉序列,每个点u进栈dfs序所对应的权值为正,出栈dfs序所对应的权值为负(绝对值都是该点u的权值)。设根为root,该点为a点,其入栈序为t1,出栈序为t2。那么树上a到root的权值和就是dfs序在1到t2-1的所对应的权值和。
证明根据欧拉序列的性质想一想应该就可以明白了(不在a到root这条链上的权值都通过一正一负抵消了)。
换父亲操作也很容易,假设将a的父亲换为b,令a的进栈出栈序分别为ta1和ta2,b的为tb1和tb2。我们只需要把ta1到ta2这段区间整体地移动到tb1后或者tb2前即可(必须要挨着tb1或tb2)。
用splay随便搞搞就可以了。
 
我的代码(可对拍,交bzoj TLE,本机O2 26s):
 #include<cstdio>
#include<cstdlib>
using namespace std; typedef long long ll;
#define maxn 200010
int n,m,cnt,stack[maxn],dfn[maxn];
int next[maxn],side[maxn],toit[maxn]; inline int Abs(int a) { if (a < ) return -a; return a; } inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
} struct SPLAY
{
ll key[maxn],sum[maxn],inc[maxn];
int size[maxn],sz[maxn],sf[maxn],ch[maxn][],fa[maxn],root; inline int find(int rest)
{
int now = root;
while (true)
{
if (rest == size[ch[now][]]+) break;
else if (rest > size[ch[now][]]+) rest -= size[ch[now][]]+,now = ch[now][];
else now = ch[now][];
}
return now;
} inline void pushdown(int now)
{
int lc = ch[now][],rc = ch[now][];
if (inc[now])
{
sum[now] += (ll)sz[now]*inc[now]-(ll)sf[now]*inc[now];
key[now] += (now <= n?:-)*inc[now];
if (lc) inc[lc] += inc[now]; if (rc) inc[rc] += inc[now];
inc[now] = ;
}
} inline void updata(int now)
{
int lc = ch[now][],rc = ch[now][];
if (lc) pushdown(lc); if (rc) pushdown(rc);
size[now] = size[lc] + size[rc] + ;
sz[now] = sz[lc] + sz[rc] + (now <= n);
sf[now] = sf[lc] + sf[rc] + (now > n);
sum[now] = sum[lc] + sum[rc] + key[now];
} inline int build(int l,int r)
{
int mid = (l + r) >> ,now = (dfn[mid]<)*n+Abs(dfn[mid]);
key[now] = (dfn[mid] < ?-:)*key[Abs(dfn[mid])];
if (l < mid)
{
ch[now][] = build(l,mid - );
fa[ch[now][]] = now;
}
if (mid < r)
{
ch[now][] = build(mid + ,r);
fa[ch[now][]] = now;
}
updata(now); return now;
} inline void init()
{
int p = (n<<)+,q = (n<<)+;
fa[q] = p; ch[p][] = q; root = p;
ch[q][] = build(,n<<); fa[ch[q][]] = q;
updata(q); updata(p);
} inline void rotate(int x)
{
int y = fa[x],z = fa[y],l = ch[y][] == x,r = l^;
if (z) ch[z][ch[z][] == y] = x; fa[x] = z;
if (ch[x][r]) fa[ch[x][r]] = y; ch[y][l] = ch[x][r];
fa[y] = x; ch[x][r] = y;
updata(y); updata(x);
} inline void splay(int x,int aim)
{
int top = ;
for (int i = x;i;i = fa[i]) stack[++top] = i;
while (top) pushdown(stack[top--]);
while (fa[x] != aim)
{
int y = fa[x],z = fa[y];
if (z != aim)
{
if ((ch[y][] == x) ^ (ch[z][] == y)) rotate(x);
else rotate(y);
}
rotate(x);
}
if (!aim) root = x;
} inline int grank(int a)
{
int ret = size[ch[a][]] + ,b = a;
for (a = fa[a];a;b = a,a = fa[a])
if (ch[a][] == b) ret += size[ch[a][]] + ;
return ret;
} inline ll calc(int a)
{
splay((n<<)+,); splay(n+a,(n<<)+);
return sum[ch[n+a][]];
} inline void add(int a,int b)
{
int p = find(grank(a)-),q = find(grank(n+a)+);
splay(p,); splay(q,p);
inc[ch[q][]] += (ll)b;
} inline void change(int a,int b)
{
int p = find(grank(a)-),q = find(grank(n+a)+);
splay(p,); splay(q,p);
int rt = ch[q][];
fa[rt] = ch[q][] = ;
updata(q); updata(p);
p = find(grank(n+b)-);
splay(b,); splay(b+n,b);
if (p != b) splay(p,b+n),fa[rt] = p,ch[p][] = rt,updata(p);
else fa[rt] = b+n,ch[b+n][] = rt;
updata(b+n); updata(b);
}
}tree; inline void add(int a,int b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; } inline void dfs(int now)
{
dfn[++cnt] = now;
for (int i = side[now];i;i = next[i]) dfs(toit[i]);
dfn[++cnt] = -now;
} int main()
{
freopen("3786.in","r",stdin);
freopen("3786.out","w",stdout);
n = read();
for (int i = ;i <= n;++i) add(read(),i);
for (int i = ;i <= n;++i) tree.key[i] = read();
cnt = ; dfs();
tree.init(); m = read();
while (m--)
{
char opt;
do opt = getchar(); while (opt != 'Q'&&opt != 'C' && opt != 'F');
if (opt == 'Q') printf("%lld\n",tree.calc(read()));
else if (opt == 'F') { int a = read(),b = read(); tree.add(a,b); }
else { int a = read(),b = read(); tree.change(a,b); }
}
fclose(stdin); fclose(stdout);
return ;
}

如果你与我一样一直TLE,也欢迎使用这份代码提交(来自:http://blog.csdn.net/jiangyuze831/article/details/41649235):

 #include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 600010
#define WORKPATH (root->son[1]->son[0])
using namespace std; struct SplayTree{
long long val,sum,c,size;
long long plus,num,_num;
SplayTree *son[],*father; SplayTree(int _,int __);
SplayTree() {}
bool Check() {
return father->son[] == this;
}
void Combine(SplayTree *a,bool dir) {
son[dir] = a;
a->father = this;
}
void Plus(int c);
void PushUp() {
sum = son[]->sum + son[]->sum + val * (plus ? :-);
size = son[]->size + son[]->size + ;
num = son[]->num + son[]->num + (plus == );
_num = son[]->_num + son[]->_num + (plus == );
}
void PushDown() {
if(c) {
son[]->Plus(c);
son[]->Plus(c);
c = ;
}
}
}none,*nil = &none,*root,*tree[MAX];
SplayTree:: SplayTree(int _,int __) {
plus = __;
if(__ == ) ++num;
if(__ == ) ++_num;
val = _;
sum = _ * (plus ? :-);
size = ;
c = ;
son[] = son[] = nil;
}
void SplayTree:: Plus(int _) {
if(this == nil) return ;
sum += _ * (num - _num);
val += _;
c += _;
} int points,asks;
int head[MAX],total;
int next[MAX],aim[MAX]; int src[MAX],pos[MAX];
int from[MAX],cnt;
int p[MAX]; char c[]; inline void Add(int x,int y)
{
next[++total] = head[x];
aim[total] = y;
head[x] = total;
} void DFS(int x)
{
pos[++cnt] = src[x];
from[cnt] = x;
p[cnt] = true;
for(int i = head[x]; i; i = next[i])
DFS(aim[i]);
pos[++cnt] = src[x];
from[cnt] = x;
p[cnt] = false;
} void Pretreatment()
{
nil->son[] = nil->son[] = nil->father = nil;
nil->val = nil->sum = nil->c = nil->size = ;
p[] = p[cnt + ] = -;
} SplayTree *BuildTree(int l,int r)
{
if(l > r) return nil;
int mid = (l + r) >> ;
SplayTree *re = new SplayTree(pos[mid],p[mid]);
if(p[mid]) tree[from[mid] << ] = re;
else tree[from[mid] << |] = re;
re->Combine(BuildTree(l,mid - ),false);
re->Combine(BuildTree(mid + ,r),true);
re->PushUp();
return re;
} inline void Rotate(SplayTree *a,bool dir)
{
SplayTree *f = a->father;
f->PushDown(),a->PushDown();
f->son[!dir] = a->son[dir];
f->son[!dir]->father = f;
a->son[dir] = f;
f->father->son[f->Check()] = a;
a->father = f->father;
f->father = a;
f->PushUp();
if(root == f) root = a;
} inline void Splay(SplayTree *a,SplayTree *aim)
{
while(a->father != aim) {
if(a->father->father == aim)
Rotate(a,!a->Check());
else if(!a->father->Check()) {
if(!a->Check())
Rotate(a->father,true),Rotate(a,true);
else Rotate(a,false),Rotate(a,true);
}
else {
if(a->Check())
Rotate(a->father,false),Rotate(a,false);
else Rotate(a,true),Rotate(a,false);
}
}
a->PushUp();
} SplayTree *Find(SplayTree *a,int k)
{
a->PushDown();
if(a->son[]->size >= k) return Find(a->son[],k);
k -= a->son[]->size;
if(k == ) return a;
return Find(a->son[],k - );
} inline void SplaySeg(SplayTree *a,SplayTree *b)
{
int size_1,size_2;
Splay(a,nil);
size_1 = root->son[]->size + ;
Splay(b,nil);
size_2 = root->son[]->size + ;
Splay(Find(root,size_1 - ),nil);
Splay(Find(root,size_2 + ),root);
} int main()
{
cin >> points;
for(int x,i = ; i <= points; ++i) {
scanf("%d",&x);
Add(x,i);
}
for(int i = ; i <= points; ++i)
scanf("%d",&src[i]);
DFS();
Pretreatment();
root = BuildTree(,cnt + );
root->father = nil;
cin >> asks;
for(int x,y,i = ; i <= asks; ++i) {
scanf("%s",c);
if(c[] == 'Q') {
scanf("%d",&x);
SplaySeg(tree[ << ],tree[x << ]);
printf("%lld\n",WORKPATH->sum);
}
else if(c[] == 'C') {
scanf("%d%d",&x,&y);
SplaySeg(tree[x << ],tree[x << |]);
SplayTree *temp = WORKPATH;
WORKPATH = nil;
root->son[]->PushUp();
root->PushUp();
Splay(tree[y << ],nil);
int k = root->son[]->size + ;
Splay(Find(root,k + ),root);
root->son[]->Combine(temp,false);
root->son[]->PushUp();
root->PushUp();
}
else {
scanf("%d%d",&x,&y);
SplaySeg(tree[x << ],tree[x << |]);
WORKPATH->Plus(y);
}
}
return ;
}

想要数据的戳这里。(里面的std可能有误,我交了一发果断RE)

BZOJ 3786 星系探索的更多相关文章

  1. BZOJ 3786: 星系探索 解题报告

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

  2. bzoj 3786 星系探索 dfs+splay

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

  3. BZOJ 3786: 星系探索 ETT

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

  4. BZOJ 3786: 星系探索 [伪ETT]

    传送门 数据,标程 题意: 一颗有根树,支持询问点到根路径权值和,子树加,换父亲 欧拉序列怎么求路径权值和? 一个点的权值只会给自己的子树中的点贡献,入栈权值正出栈权值负,求前缀和就行了! 和上题一样 ...

  5. BZOJ 3786 星系探索 ——Splay

    子树可以移动,唔. 还是用Splay维护DFS序即可. 子树的话直接截取出来就好了. 然后求前驱后继可能麻烦一些. 添加两个虚拟节点会比较好写. #include <map> #inclu ...

  6. BZOJ 3786 星系探索 (splay+dfs序)

    题目大意:给你一棵树,支持一下三种操作 1.获取某节点到根节点的路径上所有节点的权值和 2.更换某棵子树的父亲 3.某子树内所有节点的权值都增加一个值w 当时想到了splay维护dfs序,查完题解发现 ...

  7. BZOJ 3786: 星系探索 欧拉游览树

    一个叫 Euler-Tour-Tree 的数据结构,说白了就是用 Splay_Tree 维护欧拉序 #include <cstring> #include <algorithm> ...

  8. 【BZOJ】3786: 星系探索

    [题意]给定一棵带点权树,三种操作: 1.询问点x到根的路径和 2.子树x内的点权加定值y 3.将点x的父亲更换为y,保证仍是树. [算法]平衡树(fhq-treap) [题解] 将树的dfs序作为序 ...

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

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

随机推荐

  1. IE浏览器中发送到onenote的选项没有调出来??

    最近使用onenote 作为笔记本,发现这个比word好用很多,特别是还有一个功能很好用,发送到onenote,可以选中网页中的内容,发送到onenote.但是有一些IE浏览器这个选项没有调出来,还是 ...

  2. [RxJS] Combination operators: concat, startWith

    Some Observables may complete, and we may want to append another Observable to the one which just co ...

  3. Call Directory Extension 初探

    推荐序 本文介绍了 iOS 10 中的 Call Directory Extension 特性,并且最终 Demo 出一个来电黑名单的 App. 作者:余龙泽,哈工大软件工程大四学生,之前在美图公司实 ...

  4. Java基础知识强化之集合框架笔记46:Set集合之TreeSet存储自定义对象并遍历练习2(自然排序:Comparable)

    1. TreeSet存储自定义对象并遍历练习2: (1)Student.java package cn.itcast_06; /* * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口 * ...

  5. Intellij Idea 13 vmoptions (Mac版本)

    -ea -server -Xms1g -Xmx1g -Xss16m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+DoEscapeAnalysis -XX:+ ...

  6. php验证是否为手机端还是PC

    <?php $forasp = strtolower($_SERVER['HTTP_USER_AGENT']); if(strpos($forasp,'mobile')==true) { ech ...

  7. xml中报错,验证是否是xml报错

    1.xml中写入sql有时报错,例如有大于号小于号,要用<![CDATA[                  ]]>扩起来 2.验证xml有错的方式,以浏览器方式打开,如果正常打开,无错. ...

  8. 判断PHP数组是否为空的代码

    PHP判断数组为空首选方法:count($arr),size($arr); 复制代码 代码如下: $arr= array(""); echo count($arr); echo s ...

  9. Unity 5.x---00使用重力

    Unity 5.x---00使用重力 步骤一: 打开一个工程(导入Unity自带的资源),并创建并配置好必要的GameObject ,如下图: 步骤二: 1.创建一个Cube,使其位于平面上方.    ...

  10. c++文件读写相关

    在看C++编程思想中,每个练习基本都是使用ofstream,ifstream,fstream,以前粗略知道其用法和含义,在看了几位大牛的博文后,进行整理和总结: 这里主要是讨论fstream的内容: ...