【BZOJ】3786: 星系探索
【题意】给定一棵带点权树,三种操作:
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: 星系探索的更多相关文章
- BZOJ 3786: 星系探索 解题报告
3786: 星系探索 Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅 ...
- bzoj 3786 星系探索 dfs+splay
[BZOJ3786]星系探索 Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球 ...
- BZOJ 3786 星系探索
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> ...
- [BZOJ3786]星系探索(伪ETT)
3786: 星系探索 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1638 Solved: 506[Submit][Status][Discuss ...
随机推荐
- 佣金维护测试sql
SELECT bmc.memberid , case then decode(bmc.source, , , 'TOPfitIBL') ELSE decode(bmc.source, , , 'TOP ...
- [百度贴吧]10GB 通信线缆
现在,即使光纤通信能够带来最低延迟的优势,但是许多IT部门依然在10G以太网(10G bE)中使用铜缆布线,来实现交换机和交换机或者和服务器之间的连接.目前主要有两种主要的铜缆布线技术应用在10 Gb ...
- Python fullstack系列【2】Python数据类型
基本数据类型 学习一门编程语言通常都是先了解其不同的数据类型,以及每种数据类型对象所附带的方法,Python也不例外,本篇就详细介绍下这部分. Python基本数据类型总览: 1.Booleans(布 ...
- javascript中boolean类型和其他类型的转换
在javascript中,if语句括号中的表达式返回值可以是任何类型,即:if(a)中的a可以是boolean.number.string.object.function.undefined中的任何类 ...
- BZOJ3277 串(后缀数组+二分答案+主席树)
因为不会SAM,考虑SA.将所有串连起来并加分隔符,每次考虑计算以某个位置开始的子串有多少个合法. 对此首先二分答案,找到名次数组上的一个区间,那么只需要统计有多少个所给串在该区间内出现就可以了.这是 ...
- 【刷题】BZOJ 1926 [Sdoi2010]粟粟的书架
Description 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Cormen 的文章.粟粟家中有一个 R行C 列的巨型书架,书 ...
- jQuery map和each用法
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Spring点滴二:Spring Bean
Spring Bean: 被称作bean的对象是构成应用程序的支柱,是由Spring Ioc容器管理.bean是一个被实例化,配置.组装并由Spring Ioc容器管理对象. 官网API:A Spri ...
- hdu2138 Miller_Rabin
Description Give you a lot of positive integers, just to find out how many prime numbers there are ...
- Stamp Rally
Stamp Rally 最大值最小,可以二分,然后并查集看能不能到z个点 但是询问过多,并且发现每次二分要加入的点并不是所有的m条边 于是就考虑整体二分 并查集的处理是重点: 对于一般的dfs分治树, ...