【题意】给定一棵带点权树,三种操作:

1.询问点x到根的路径和

2.子树x内的点权加定值y

3.将点x的父亲更换为y,保证仍是树。

【算法】平衡树(fhq-treap)

【题解】

将树的dfs序作为序列维护,对每个点入栈+1,出栈-1,这样操作1就是前缀和(非此路径的都会正负抵消),操作2就是区间加值,操作3就是区间移动,可以用平衡树维护。

具体实现:原树上每个点在序列中对应两个点(入栈和出栈),每个点维护自身系数(1或-1),自身数值(含系数),系数和,数值和。维护系数是为了满足通过标记直接修改sum。

还有一个问题,只知道点的编号如何查询点的排名,实际上就是左子树+往上左走时的所有左子树(均含本点)。

过程中,在up处更新左右节点的父亲即可,但要额外更新分裂合并时根节点的父亲。

记得开long long。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=;
struct cyc{int l,r,rnd,sz,fa,gnum,gsum;ll delta,num,sum;}t[maxn];
struct edge{int v,from;}e[maxn];
int tote=,first[maxn];
void insert(int u,int v){tote++;e[tote].v=v;e[tote].from=first[u];first[u]=tote;}
int n,m,be[maxn],ed[maxn],tot,a[maxn],b[maxn],c[maxn],st[maxn],root;
int read(){
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
void dfs(int x){
be[x]=++tot;b[tot]=;c[tot]=a[x];
for(int i=first[x];i;i=e[i].from){
dfs(e[i].v);
}
ed[x]=++tot;b[tot]=-;c[tot]=-a[x];
}
void up(int k){
t[k].sz=+t[t[k].l].sz+t[t[k].r].sz;
t[k].gsum=t[k].gnum+t[t[k].l].gsum+t[t[k].r].gsum;
t[k].sum=t[k].num+t[t[k].l].sum+t[t[k].r].sum;
if(t[k].l)t[t[k].l].fa=k;
if(t[k].r)t[t[k].r].fa=k;
}
void modify(int k,int x){t[k].num+=1ll*t[k].gnum*x;t[k].sum+=1ll*t[k].gsum*x;t[k].delta+=x;}
void down(int k){
if(t[k].delta){
modify(t[k].l,t[k].delta);modify(t[k].r,t[k].delta);
t[k].delta=;
}
}
void DFS(int k){
if(!k)return;
DFS(t[k].l);DFS(t[k].r);
up(k);
}
void build(){
int top=;
for(int i=;i<=tot;i++){
t[i]=(cyc){,,rand(),,,b[i],b[i],,c[i],c[i]};
while(top&&t[st[top]].rnd>t[i].rnd){
t[st[top]].r=t[i].l;
t[i].l=st[top--];
}
t[st[top]].r=i;
st[++top]=i;
}
t[]=(cyc){,,,,,,,,};
DFS(root=st[]);
t[root].fa=;
}
int find(int x){
int sum=t[t[x].l].sz+;
while(t[x].fa!=){
if(t[t[x].fa].r==x)sum+=t[t[t[x].fa].l].sz+;
x=t[x].fa;
}
return sum;
}
int merge(int a,int b){
if(!a||!b)return a^b;
if(t[a].rnd<t[b].rnd){
down(a);
t[a].r=merge(t[a].r,b);
up(a);
return a;
}
else{
down(b);
t[b].l=merge(a,t[b].l);
up(b);
return b;
}
}
void split(int k,int &l,int &r,int x){
if(!k)return void(l=r=);
down(k);
if(x<t[t[k].l].sz+){
r=k;
split(t[k].l,l,t[k].l,x);
}
else{
l=k;
split(t[k].r,t[k].r,r,x-t[t[k].l].sz-);
}
up(k);
}
ll goroot(int x){
int a,b;
split(root,a,b,find(be[x]));
ll ans=t[a].sum;
root=merge(a,b);
t[root].fa=;
return ans;
}
void change(int x,int y){
int a,b,c;
split(root,b,c,find(ed[x]));t[b].fa=t[c].fa=;
split(b,a,b,find(be[x])-);t[a].fa=t[b].fa=;
modify(b,y);
root=merge(a,b);
root=merge(root,c);
t[root].fa=;
}
void move(int x,int y){
int a,b,c;
split(root,b,c,find(ed[x]));t[b].fa=t[c].fa=;
split(b,a,b,find(be[x])-);t[a].fa=t[b].fa=;
root=merge(a,c);
t[root].fa=;
split(root,a,c,find(be[y]));t[a].fa=t[c].fa=;
root=merge(a,b);
root=merge(root,c);
t[root].fa=;
}
char s[];
int main(){
srand();
n=read();
for(int i=;i<=n;i++)insert(read(),i);
for(int i=;i<=n;i++)a[i]=read();
dfs();build();
m=read();
for(int i=;i<=m;i++){
scanf("%s",s);
int x=read();
if(s[]=='Q'){
printf("%lld\n",goroot(x));
}
if(s[]=='C'){
int y=read();
move(x,y);
}
if(s[]=='F'){
int y=read();
change(x,y);
}
}
return ;
}

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

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

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

  2. bzoj 3786 星系探索 dfs+splay

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

  3. BZOJ 3786 星系探索

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

  4. BZOJ 3786: 星系探索 ETT

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

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

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

  6. BZOJ 3786 星系探索 ——Splay

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

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

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

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

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

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

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

随机推荐

  1. json对象与json字符串的区别

    最近糟了这个坑,同一个方法,android和ios返回的数据不一样,一个是json字符串,另一个是json对象(至于为什么后台返回的是json对象,还没找到原因,但是我看到的后台的代码是有在返回之前给 ...

  2. 减小Delphi 2010/delphi XE编译出来的文件大小

    1.禁用RTTI 禁用的方法很简单,就是要在工程(dpr文件中.Delphi2010下项目文件是dproj文件,但dpr文件仍然是默认的编写代码的项目文件)的Uses语句前添加下面的定义就可以了: { ...

  3. windows多线程(二) 等待线程返回

    多线程编程中,有时我们需要等待某一线程完成了特定的操作后再继续做其他事情,要实现这个目的,可以使用Windows API函数WaitForSingleObject,或者WaitForMultipleO ...

  4. Android中线程间通信原理分析:Looper,MessageQueue,Handler

    自问自答的两个问题 在我们去讨论Handler,Looper,MessageQueue的关系之前,我们需要先问两个问题: 1.这一套东西搞出来是为了解决什么问题呢? 2.如果让我们来解决这个问题该怎么 ...

  5. matlab for 运算的提速

    [1]主要思想:matlab是按列存储,定义s(nums,1)比定义s(1,nums)要快哦                       需要重复query的元素看看能不能再for之前就定义好 经典案 ...

  6. Java容器深入浅出之HashSet、TreeSet和EnumSet

    Java集合中的Set接口,定义的是一类无顺序的.不可重复的对象集合.如果尝试添加相同的元素,add()方法会返回false,同时添加失败.Set接口包括3个主要的实现类:HashSet.TreeSe ...

  7. command symbol & mac & emoji

    command symbol & mac & emoji how to input command symbol in mac ? https://apple.stackexchang ...

  8. vi命令文件编辑

    vi命令是UNIX操作系统和类UNIX操作系统中最通用的全屏幕纯文本编辑器. Linux中的vi编辑器叫vim,它是vi的增强版(vi Improved),与vi编辑器完全兼容,而且实现了很多增强功能 ...

  9. Python 字节码是什么

    了解 Python 字节码是什么,Python 如何使用它来执行你的代码,以及知道它是如何帮到你的. 如果你曾经编写过 Python,或者只是使用过 Python,你或许经常会看到 Python 源代 ...

  10. 学习操作Mac OS 之安装工具组件

    视频软件: MPlayerX 安装MySQL: 下载MySQL: https://dev.mysql.com/downloads/installer/ 设置环境变量:http://www.cnblog ...