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

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=400010;
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=0,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=0,t=1;while(!isdigit(c=getchar()))if(c=='-')t=-1;do{s=s*10+c-'0';}while(isdigit(c=getchar()));return s*t;
}
void dfs(int x){be[x]=++tot;b[tot]=1;c[tot]=a[x];for(int i=first[x];i;i=e[i].from){dfs(e[i].v);}ed[x]=++tot;b[tot]=-1;c[tot]=-a[x];
}
void up(int k){t[k].sz=1+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=0;}
}
void DFS(int k){if(!k)return;DFS(t[k].l);DFS(t[k].r);up(k);
}
void build(){int top=0;for(int i=1;i<=tot;i++){t[i]=(cyc){0,0,rand(),1,0,b[i],b[i],0,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[0]=(cyc){0,0,0,0,0,0,0,0,0};DFS(root=st[1]);t[root].fa=0;
}
int find(int x){int sum=t[t[x].l].sz+1;while(t[x].fa!=0){if(t[t[x].fa].r==x)sum+=t[t[t[x].fa].l].sz+1;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=0);down(k);if(x<t[t[k].l].sz+1){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-1);}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=0;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=0;split(b,a,b,find(be[x])-1);t[a].fa=t[b].fa=0;modify(b,y);root=merge(a,b);root=merge(root,c);t[root].fa=0;
}
void move(int x,int y){int a,b,c;split(root,b,c,find(ed[x]));t[b].fa=t[c].fa=0;split(b,a,b,find(be[x])-1);t[a].fa=t[b].fa=0;root=merge(a,c);t[root].fa=0;split(root,a,c,find(be[y]));t[a].fa=t[c].fa=0;root=merge(a,b);root=merge(root,c);t[root].fa=0;
}
char s[10];
int main(){srand(233);n=read();for(int i=2;i<=n;i++)insert(read(),i);for(int i=1;i<=n;i++)a[i]=read();dfs(1);build();m=read();for(int i=1;i<=m;i++){scanf("%s",s);int x=read();if(s[0]=='Q'){printf("%lld\n",goroot(x));}if(s[0]=='C'){int y=read();move(x,y);}if(s[0]=='F'){int y=read();change(x,y);}}return 0;
}

View Code

转载于:https://www.cnblogs.com/onioncyc/p/7967609.html

【BZOJ】3786: 星系探索相关推荐

  1. BZOJ#3786. 星系探索(平衡树,fhq-treap,弱化版ETT)

    BZOJ#3786. 星系探索 Solution 子树加,换fatherfatherfather(保证还是树),询问到根路径和. 树上路径求和不好动态维护,于是转化到序列上,维护一个括号序,dfndf ...

  2. [BZOJ 3786] 星系探索

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

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

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

  4. bzoj3786星系探索 splay

    3786: 星系探索 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1314  Solved: 425 [Submit][Status][Discu ...

  5. android探索宇宙app,AR研学星系探索app

    AR研学星系探索app是一款为喜欢探索宇宙的用户们提供的关于八大行星学习的软件:通过VR虚拟的形式让用户可以更加直观地了解到我们的地球和我们的浩瀚的宇宙,来启发用户对宇宙的探索和好奇.这款软件会为用户 ...

  6. [BZOJ3786]星系探索

    星系探索 题解 一道ETT板子题 笔者最开始用FHQ_Treap打的ETT,忘记可以沿 f a fa fa算出它的欧拉序,一直没调出来,于是就改用splay了. ETT的模板.其实我觉得叫它平衡树板子 ...

  7. bzoj3786星系探索(splay维护dfs序)

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

  8. bzoj3786: 星系探索

    学到了新姿势,splay维护括号序列(听说是伪ETT(euler-tour-tree 欧拉搜索树)?) 大型工业题 注意点:1:结构改变了以后编号变成不连续的了,要找前驱和后继 2:就算lazy也需要 ...

  9. 平衡二叉树 treap

    treap通过左右旋维护了一个二叉查找树,根据随机的优先级建立满足优先级大根堆的二叉查找树,在实践中有不错的食府,code也简单. cogs1829 普通平衡树 题目大意:进行插入.删除.名次.前驱后 ...

  10. PKUSC2018训练日程(4.18~5.30)

    (总计:共66题) 4.18~4.25:19题 4.26~5.2:17题 5.3~5.9: 6题 5.10~5.16: 6题 5.17~5.23: 9题 5.24~5.30: 9题 4.18 [BZO ...

最新文章

  1. 微软、IBM们的中国研究院是怎样一步步“躺平”的?
  2. ACM 未解决的问题
  3. 联想家庭云中心:天边飘来“故乡的云”
  4. 最全的IO操作知识总结
  5. Android 11 正式版发布!
  6. 7.业务架构·应用架构·数据架构实战 --- 业务架构书
  7. EmbossMaskFilter BlurMaskFilter 学习
  8. ZT[记那对住在我隔壁储藏室的大学刚毕业的小夫妻]
  9. 【深度长文】中国电子商务简史:1999-2019
  10. Linux Oracle卸载步骤
  11. matlab uigetfile
  12. 加速基于flash的嵌入式应用程序
  13. eplan窗口宏与符号宏是什么_电气设计||Eplan P8 宏功能的应用
  14. 物联网Wifi三大新主流势均力敌 SIP时代即将来袭
  15. UDIMM、RDIMM、SODIMM区别
  16. 全球与中国pH控制剂市场现状及未来发展趋势(2022)
  17. 切图工具:输出512*512切片大小的切片
  18. java 如何循环执行一个对象_养猪场循环生态循环模式及其效益分析,当前牧草成为生态循环猪场效益更好的选择,如何打造一个现代生态循环的高效益猪场?...
  19. 【面试】面试常问之堆栈的区别
  20. 多线程面试题(高薪高频)

热门文章

  1. C++之string的底层真的是用char数组来实现的么?
  2. 按位与、或、异或等运算方法(转)
  3. java模式之工厂模式
  4. Android 开机充电图标和充电动画
  5. FreeSWITCH黑名单功能设置
  6. linux的审计功能(audit)
  7. mysql 分区 range_Mysql分区|mysql分区表|mysql partition|by range
  8. Partition List 将链表分成两部分
  9. 反转字符串 不同方式
  10. 学习手记——技术博文汇总(持续更新)