【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 ...
随机推荐
- vm的三种网络模式
Vm网卡的模式:网络地址转换模式(nat),仅主机(host-only),桥接模式(Brideged) VMware 的几个虚拟设备: ■ VMnet0:这是 VMware 用于虚拟桥接网络下的虚拟交 ...
- 2012r2 以及 2012r2 withupdate 已经安装更新的差异
0. 2012r2 不管带不带 update 1 他的版本号 都是 6.3.9600 如图示 2012r2的发布时间是 2013年 2012r2withupdate的发布时间是 2014年. 查看补丁 ...
- poj 2942 Knights of the Round Table(点双连通分量+二分图判定)
题目链接:http://poj.org/problem?id=2942 题意:n个骑士要举行圆桌会议,但是有些骑士相互仇视,必须满足以下两个条件才能举行: (1)任何两个互相仇视的骑士不能相邻,每个骑 ...
- POJ3177_Redundant Paths
给你一个无向图,求至少加入多少条边,使得整个图是双联通的. 通过枚举题意,发现重边是不算的,直接去掉. 首先把那些边是桥计算出来,把位于同一个连通分量里面的点缩成一个点(并查集),然后计算缩点后有多少 ...
- BZOJ2339 HNOI2011卡农(动态规划+组合数学)
考虑有序选择各子集,最后除以m!即可.设f[i]为选i个子集的合法方案数. 对f[i]考虑容斥,先只满足所有元素出现次数为偶数.确定前i-1个子集后第i个子集是确定的,那么方案数为A(2n-1,i-1 ...
- springboot整合spring @Cache和Redis
转载请注明出处:https://www.cnblogs.com/wenjunwei/p/10779450.html spring基于注解的缓存 对于缓存声明,spring的缓存提供了一组java注解: ...
- Springboot返回html
注:Springboot的版本2.1.3.RELEASE List-1 application.properties文件 server.port=8080 #url中,项目的前缀 server.ser ...
- 【Cf #291 B】R2D2 and Droid Army(二分,线段树)
因为题目中要求使连续死亡的机器人最多,令人联想到二分答案. 考虑如何检验这之中是否存在一段连续的长度为md的区间,其中花最多k步使得它们都死亡. 这个条件等价于区间中m个最大值的和不超过k. 枚举起点 ...
- 洛谷 P1356 数列的整数性 解题报告
P1356 数列的整数性 题目描述 对于任意一个整数数列,我们可以在每两个整数中间任意放一个符号'+'或'-',这样就可以构成一个表达式,也就可以计算出表达式的值.比如,现在有一个整数数列:17,5, ...
- 【codeforces 765F】 Souvenirs
http://codeforces.com/problemset/problem/765/F (题目链接) 题意 给出$n$个数的序列,$m$次询问,每次查询区间$[l,r]$之间相差最小的两个数的差 ...