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 ...
随机推荐
- android uri , file , string 互转
1:android Uri 介绍 http://www.cnblogs.com/lingyun1120/archive/2012/04/18/2455212.html 2:File 转成Uri < ...
- I/O体系结构和设备驱动程序
http://blog.csdn.net/kafeiflynn/article/category/789844
- OOP 概述
面向对象程序设计基于四个基本概念:数据抽象.封装.继承和动态绑定. 类的基本思想是数据抽象和封装. 1 数据抽象 数据抽象是一种依赖于接口和实现分离的编程技术.类的接口包括用户所能执行的操作:类的实现 ...
- Linux进程学习(孤儿进程和守护进程)
孤儿进程和守护进程 通过前面的学习我们了解了如何通过fork()函数和vfork()函数来创建一个进程.现在 我们继续深入来学习两个特殊的进程:孤儿进程和守护进程 一.孤儿进程 1.什么是 孤儿进程如 ...
- MapReduce 运行机制
Hadoop中的MapReduce是一个使用简单的软件框架,基于它写出来的应用程序能够运行在由上千个机器组成的大型集群上,并且以一种可靠容错并行处理TB级别的数据集. 一个MapReduce作业(jo ...
- mysql 异常处理实例
1. 语法: DECLARE handler_action HANDLER FOR condition_value [, condition_value] ... statement handler_ ...
- freemarker if..else.. 的使用
FreeMarker是一款模板引擎,今天在做Pad端的时候正好用到,用法非常简单: 在xml配置页面的文件中,直接使用 <#if 1=1> //条件成立要显示的内容 </#if> ...
- Python数据类型(元组、列表、字符串、字典)
元组tuple:不可修改的数据类型 ABC = ('a', 1, x, 'today') 列表list:可修改的数据类型 ABC = ['a', 1, x, 'today'] 字符串set: ABC ...
- Maven学习总结——聚合与继承
一.聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1.1.聚合配置代码 1 <modules> 2 <module>模块一</module&g ...
- java读取redis的timeout异常
http://blog.csdn.net/shuaiokshuai/article/details/23266091 FIFO Fist-in Fisrt-out 先进先出