【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 ...
随机推荐
- sed ,awk , cut三剑客的区别
sed: sed只能截取文件中以行的来截取数据,,(grep命令可以过滤到某一行) 例如: [root@localhost ~]# sed -n '2,3p' /etc/passwd ...
- Internet History, Technology and Security (Week 8)
Week 8 Security: Encrypting and Signing This week we start two weeks of Internet Security. It is a l ...
- Alpha阶段敏捷冲刺①Scrum 冲刺博客
第 1 篇 Scrum 冲刺博客对整个冲刺阶段起到领航作用,应该主要包含三个部分的内容: 各个成员在 Alpha 阶段认领的任务 成员 任务 张晨晨 完成界面设计(前端) 黄登峰 完成界面设计(前端) ...
- Teamcity部署.net服务“无法连接到远程服务器”解决方式
在公司Teamcity上执行自动部署.net服务的时候,发现Teamcity在启动default.aspx的时候报错了,提示:使用“0”个参数调用“GetResponse”时发生异常:“无法连接到远程 ...
- [转帖]中国SaaS死或生之一:“网红”CRM的大起大落
中国SaaS死或生之一:“网红”CRM的大起大落 http://www.cniteyes.com/archives/33709 文章摘要:从“大众情人”到被人遗弃,如何从CRM身上审视中国Sa ...
- SQLSERVER2017 最新补丁发布方式
SQLSERVER2017 开始已经没有 SP service pack 包了. 取而代之的是CU 包 cumulative update 见: https://support.microsoft.c ...
- [转发]VMware厚置备延迟置零 、 厚置备置零、精简置备 区别
1.厚置备延迟置零(zeroed thick) 以默认的厚格式创建虚拟磁盘.创建过程中为虚拟磁盘分配所需空间.创建时不会擦除物理设备上保留的任何数据,但是以后从虚拟机首次执行写操作时会按需要将其置零. ...
- UVA10054_The Necklace
很简单,求欧拉回路.并且输出. 只重点说一下要用栈来控制输出. 为啥,如图: 如果不用栈,那么1->2->3->1就回来了,接着又输出4->5,发现这根本连接不上去,所以如果用 ...
- 【JavaScript】table里面点击某td获取同一行tr的其他td值
某td的input(保存按钮)上绑定方法,点击按钮保存该行所有数据 function locationedit(num){ var ordernumber = $("#"+num) ...
- URAL 1969. Hong Kong Tram
有一个trick就是没想到,枚举第二段时间后,要检测该火车能否继续跑一圈来判断,不能先检测前半圈能不能跑加进去后在检测后半段: // **** 部分不能放在那个位置: 最近代码导致的错误总是找不出,贴 ...