BZOJ 1036 [ZJOI2008]树的统计Count(动态树)
2016-05-28 17:18
323 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036
题意:一棵树,每个节点有一个权值。三种操作:(1)修改某个节点的权值;(2)输出某两个节点之间的权值之和;(3)输出某两个节点之间权值的最大值。
思路:(1)首先说明,在splay中记录一个father,表示当前节点的父节点。但是在这里,在一个树链中,father与在splay中的father的意义是一样的,也就是设v的father是u,那么u的左孩子或者右孩子必然有一个是v。但是,若v和u不在一个树链中,那么u表示v所在树链的最上面的顶点的父节点。也就是此时u的左孩子和右孩子都不是v,u和v属于两个树链;
(2)在一个树链中v的左孩子是在v上面的顶点,也就是在原树中这些点都是v的父节点以及祖宗节点;右孩子是v下面的顶点,也就是原树中v的孩子以及子孙节点。当然不管右孩子还是左孩子都是当前与v在一个树链中的;
(3)splay(x)将x旋转到x所在的树链的根,access(x)将x和root(这个root才是真正的树根)的边变为实边。在access(x)时,首先要断开x与其右孩子Xr的关联(在(4)中我们解释为什么要断开),并将Xr的father设为x,那么此时,Xr将成为一个树链的根;接着对于v的父节点u,因为要将u的右孩子变为v,所以之前u的右孩子(若有)Ur要与其断开并将Ur的father设为u,此时Ur将成为其所在树链的根;接着将u的右孩子设为v。一直向上直到root;
(4)每次计算(x,y)的最大或者和时,首先access(x)将x和root之间的边变为实边,然后access(y)此时返回值就是p=Lca(x,y)。想想为什么是这样?因为Lca(x,y)已经跟x在一个树链上了,因为我们已经access(x)了。现在从y开始向上找时,对于其father节点z,首先会splay(z)将z转到其所在树链的根节点,那么若z是Lca(x,y),那么z必然将成为树根,也就是root,那么其father节点为null。现在我们说明白了返回值为什么是 Lca(x,y)。接着p会与x断开,因为x在p的右孩子或者右孩子以下,p的右孩子将变成y所以断开了。此时若将splay(x),那么x就是p到x路径(不包含p)组成的树链的根,并且不会包含x以下的部分,在(3)中我们知道,x向上access时x与其右孩子已经断开。那么用x的sum以及p的val以及p的右孩子也就是y的sum就能计算出x到y的和。
题意:一棵树,每个节点有一个权值。三种操作:(1)修改某个节点的权值;(2)输出某两个节点之间的权值之和;(3)输出某两个节点之间权值的最大值。
思路:(1)首先说明,在splay中记录一个father,表示当前节点的父节点。但是在这里,在一个树链中,father与在splay中的father的意义是一样的,也就是设v的father是u,那么u的左孩子或者右孩子必然有一个是v。但是,若v和u不在一个树链中,那么u表示v所在树链的最上面的顶点的父节点。也就是此时u的左孩子和右孩子都不是v,u和v属于两个树链;
(2)在一个树链中v的左孩子是在v上面的顶点,也就是在原树中这些点都是v的父节点以及祖宗节点;右孩子是v下面的顶点,也就是原树中v的孩子以及子孙节点。当然不管右孩子还是左孩子都是当前与v在一个树链中的;
(3)splay(x)将x旋转到x所在的树链的根,access(x)将x和root(这个root才是真正的树根)的边变为实边。在access(x)时,首先要断开x与其右孩子Xr的关联(在(4)中我们解释为什么要断开),并将Xr的father设为x,那么此时,Xr将成为一个树链的根;接着对于v的父节点u,因为要将u的右孩子变为v,所以之前u的右孩子(若有)Ur要与其断开并将Ur的father设为u,此时Ur将成为其所在树链的根;接着将u的右孩子设为v。一直向上直到root;
(4)每次计算(x,y)的最大或者和时,首先access(x)将x和root之间的边变为实边,然后access(y)此时返回值就是p=Lca(x,y)。想想为什么是这样?因为Lca(x,y)已经跟x在一个树链上了,因为我们已经access(x)了。现在从y开始向上找时,对于其father节点z,首先会splay(z)将z转到其所在树链的根节点,那么若z是Lca(x,y),那么z必然将成为树根,也就是root,那么其father节点为null。现在我们说明白了返回值为什么是 Lca(x,y)。接着p会与x断开,因为x在p的右孩子或者右孩子以下,p的右孩子将变成y所以断开了。此时若将splay(x),那么x就是p到x路径(不包含p)组成的树链的根,并且不会包含x以下的部分,在(3)中我们知道,x向上access时x与其右孩子已经断开。那么用x的sum以及p的val以及p的右孩子也就是y的sum就能计算出x到y的和。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<string> #include<algorithm> long long w[60005],sum[60005],mx[60005]; int fa[60005],ch[60005][2],st[60005]; int u[200005],v[200005],n,m,rev[60005],x,y; void updata(int x){ int l=ch[x][0],r=ch[x][1]; sum[x]=w[x]+sum[l]+sum[r]; mx[x]=std::max(w[x],std::max(mx[l],mx[r])); } void pushdown(int x){ int l=ch[x][0],r=ch[x][1]; if (rev[x]){ rev[x]^=1; rev[l]^=1; rev[r]^=1; std::swap(ch[x][1],ch[x][0]); } } bool pd(int x){ return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; } void rotate(int x){ int y=fa[x],z=fa[y],l,r; if (ch[y][0]==x) l=0;else l=1;r=l^1; if (!pd(y)){ if (ch[z][0]==y) ch[z][0]=x;else ch[z][1]=x; } fa[x]=z;fa[y]=x;fa[ch[x][r]]=y; ch[y][l]=ch[x][r];ch[x][r]=y; updata(y);updata(x); } void splay(int x){ int top=0;st[++top]=x; for (int i=x;!pd(i);i=fa[i]){ st[++top]=fa[i]; } for (int i=top;i;i--) pushdown(st[i]); while (!pd(x)){ int y=fa[x],z=fa[y]; if (!pd(y)){ if (ch[y][0]==x^ch[z][0]==y) rotate(x); else rotate(y); } rotate(x); } } void access(int x){ for (int t=0;x;t=x,x=fa[x]){ splay(x); ch[x][1]=t; updata(x); } } void makeroot(int x){ access(x);splay(x);rev[x]^=1; } void link(int x,int y){ makeroot(x); fa[x]=y; } int main(){ scanf("%d",&n);mx[0]=-0x7fffffff; for (int i=1;i<n;i++){ scanf("%d%d",&u[i],&v[i]); } for (int i=1;i<=n;i++){ scanf("%lld",&w[i]); sum[i]=mx[i]=w[i]; } for (int i=1;i<n;i++){ link(u[i],v[i]); } scanf("%d",&m); char s[20]; for (int i=1;i<=m;i++){ scanf("%s%d%d",s,&x,&y); if (s[1]=='H'){ splay(x); w[x]=y; updata(x); } else if (s[1]=='M'){ makeroot(x); access(y); splay(y); printf("%lld\n",mx[y]); } else{ makeroot(x); access(y); splay(y); printf("%lld\n",sum[y]); } } }
相关文章推荐
- 防止短连接耗尽你的动态TCP端口
- nginx配置location总结及rewrite规则写法
- Struts2 标签的使用
- Struts2 标签的使用
- Struts2 标签的使用
- Struts2 标签的使用
- POJ 2411 Mondriaan's Dream(状态压缩DP)
- 【java】显示刽子手游戏画面
- Proxy动态代理
- [从头学数学] 第228节 函数与极限
- 六,可变变量
- 动态创建二维数组
- 个人书单
- SQL注入详解
- 设计模式之适配器模式(Adapter)
- centos下安装五笔输入法的教程
- phpadmin关于空密码的修改
- Add Binary
- 浅入DNS
- HDU_1085_Holding Bin-Laden Captive!_母函数