BZOJ 3786 星系探索
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
1
1
4 5 7
5
Q 2
F 1 3
Q 2
C 2 3
Q 2
Sample Output
15
25
HINT
n<=100000,m<=300000,1<di,xi<=n,wi,qi<=100000.保证操作合法。
#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 星系探索的更多相关文章
- BZOJ 3786: 星系探索 解题报告
3786: 星系探索 Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅 ...
- bzoj 3786 星系探索 dfs+splay
[BZOJ3786]星系探索 Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球 ...
- BZOJ 3786: 星系探索 ETT
Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球 ...
- BZOJ 3786: 星系探索 [伪ETT]
传送门 数据,标程 题意: 一颗有根树,支持询问点到根路径权值和,子树加,换父亲 欧拉序列怎么求路径权值和? 一个点的权值只会给自己的子树中的点贡献,入栈权值正出栈权值负,求前缀和就行了! 和上题一样 ...
- BZOJ 3786 星系探索 ——Splay
子树可以移动,唔. 还是用Splay维护DFS序即可. 子树的话直接截取出来就好了. 然后求前驱后继可能麻烦一些. 添加两个虚拟节点会比较好写. #include <map> #inclu ...
- BZOJ 3786 星系探索 (splay+dfs序)
题目大意:给你一棵树,支持一下三种操作 1.获取某节点到根节点的路径上所有节点的权值和 2.更换某棵子树的父亲 3.某子树内所有节点的权值都增加一个值w 当时想到了splay维护dfs序,查完题解发现 ...
- BZOJ 3786: 星系探索 欧拉游览树
一个叫 Euler-Tour-Tree 的数据结构,说白了就是用 Splay_Tree 维护欧拉序 #include <cstring> #include <algorithm> ...
- 【BZOJ】3786: 星系探索
[题意]给定一棵带点权树,三种操作: 1.询问点x到根的路径和 2.子树x内的点权加定值y 3.将点x的父亲更换为y,保证仍是树. [算法]平衡树(fhq-treap) [题解] 将树的dfs序作为序 ...
- [BZOJ3786]星系探索(伪ETT)
3786: 星系探索 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1638 Solved: 506[Submit][Status][Discuss ...
随机推荐
- IE浏览器中发送到onenote的选项没有调出来??
最近使用onenote 作为笔记本,发现这个比word好用很多,特别是还有一个功能很好用,发送到onenote,可以选中网页中的内容,发送到onenote.但是有一些IE浏览器这个选项没有调出来,还是 ...
- [RxJS] Combination operators: concat, startWith
Some Observables may complete, and we may want to append another Observable to the one which just co ...
- Call Directory Extension 初探
推荐序 本文介绍了 iOS 10 中的 Call Directory Extension 特性,并且最终 Demo 出一个来电黑名单的 App. 作者:余龙泽,哈工大软件工程大四学生,之前在美图公司实 ...
- Java基础知识强化之集合框架笔记46:Set集合之TreeSet存储自定义对象并遍历练习2(自然排序:Comparable)
1. TreeSet存储自定义对象并遍历练习2: (1)Student.java package cn.itcast_06; /* * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口 * ...
- Intellij Idea 13 vmoptions (Mac版本)
-ea -server -Xms1g -Xmx1g -Xss16m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+DoEscapeAnalysis -XX:+ ...
- php验证是否为手机端还是PC
<?php $forasp = strtolower($_SERVER['HTTP_USER_AGENT']); if(strpos($forasp,'mobile')==true) { ech ...
- xml中报错,验证是否是xml报错
1.xml中写入sql有时报错,例如有大于号小于号,要用<![CDATA[ ]]>扩起来 2.验证xml有错的方式,以浏览器方式打开,如果正常打开,无错. ...
- 判断PHP数组是否为空的代码
PHP判断数组为空首选方法:count($arr),size($arr); 复制代码 代码如下: $arr= array(""); echo count($arr); echo s ...
- Unity 5.x---00使用重力
Unity 5.x---00使用重力 步骤一: 打开一个工程(导入Unity自带的资源),并创建并配置好必要的GameObject ,如下图: 步骤二: 1.创建一个Cube,使其位于平面上方. ...
- c++文件读写相关
在看C++编程思想中,每个练习基本都是使用ofstream,ifstream,fstream,以前粗略知道其用法和含义,在看了几位大牛的博文后,进行整理和总结: 这里主要是讨论fstream的内容: ...