[树链剖分]bzoj 4034—— [HAOI2015]树上操作
来源:互联网 发布:yellow submarine 知乎 编辑:程序博客网 时间:2024/06/09 07:15
题目描述
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
解题思路
树链剖分的裸题。
更改一棵子树的值,就是在DFS序上更改一段区间。
询问时,每条重链其实也可以看成一段区间,构造DFS先遍历重儿子就可以了。
所以线段树维护就可以了。
#include<cstdio>#include<algorithm>#define LL long longusing namespace std;const int maxn=100005,maxm=200005;int nxt[maxm],son[maxm],lnk[maxn],f[maxn],s[maxn],w[maxn],h[maxn],dep[maxn],id[maxn],who[maxn],top[maxn];int n,Q,tot;struct jz{ int L,R; LL sum,tag;}a[maxn*4];inline int _read(){ int num=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar(); return num*f;}void add(int x,int y){nxt[++tot]=lnk[x];lnk[x]=tot;son[tot]=y;}void dfs1(int x){ s[x]=1;dep[x]=dep[f[x]]+1; for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=f[x]){ f[son[j]]=x;dfs1(son[j]); if (s[son[j]]>s[h[x]]) h[x]=son[j]; s[x]+=s[son[j]]; }}void dfs2(int x,int lst){ id[x]=++tot;who[tot]=x;top[x]=lst; if (h[x]!=0) dfs2(h[x],lst); for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=f[x]&&son[j]!=h[x]) dfs2(son[j],son[j]);}void Build(int x,int L,int R){ a[x].L=L;a[x].R=R; if (L==R){a[x].sum=w[who[L]];return;} int mid=L+(R-L>>1); Build(x*2,L,mid);Build(x*2+1,mid+1,R); a[x].sum=a[x*2].sum+a[x*2+1].sum;}void Pushdown(int x){ if (a[x].L==a[x].R) return; LL tag=a[x].tag;a[x].tag=0; a[x*2].tag+=tag;a[x*2+1].tag+=tag; a[x*2].sum+=tag*(a[x*2].R-a[x*2].L+1); a[x*2+1].sum+=tag*(a[x*2+1].R-a[x*2+1].L+1);}void change(int x,int L,int R,int y){ Pushdown(x); if (L==a[x].L&&R==a[x].R){a[x].sum+=(LL)y*(R-L+1);a[x].tag=y;return;} int mid=a[x].L+(a[x].R-a[x].L>>1); if (R<=mid) change(x*2,L,R,y);else if (L>mid) change(x*2+1,L,R,y);else {change(x*2,L,mid,y);change(x*2+1,mid+1,R,y);} a[x].sum=a[x*2].sum+a[x*2+1].sum;}LL query(int x,int L,int R){ Pushdown(x); if (L==a[x].L&&R==a[x].R) return a[x].sum; int mid=a[x].L+(a[x].R-a[x].L>>1); if (R<=mid) return query(x*2,L,R);else if (L>mid) return query(x*2+1,L,R);else return query(x*2,L,mid)+query(x*2+1,mid+1,R); a[x].sum=a[x*2].sum+a[x*2+1].sum;}void ask(int x,int y){ LL num=0; while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]]) swap(x,y); num+=query(1,id[top[x]],id[x]); x=f[top[x]]; } if (dep[x]>dep[y]) swap(x,y); num+=query(1,id[x],id[y]); printf("%lld\n",num);}int main(){ freopen("exam.in","r",stdin); freopen("exam.out","w",stdout); n=_read();Q=_read(); for (int i=1;i<=n;i++) w[i]=_read(); for (int i=1;i<n;i++){ int x=_read(),y=_read(); add(x,y);add(y,x); } dfs1(1);tot=0;dfs2(1,1); Build(1,1,n); while (Q--){ int x=_read(),y=_read(),z; if (x==1) z=_read(),change(1,id[y],id[y],z);else if (x==2) z=_read(),change(1,id[y],id[y]+s[y]-1,z);else if (x==3) ask(1,y); } return 0;}
阅读全文
0 0
- [树链剖分]bzoj 4034—— [HAOI2015]树上操作
- bzoj 4034: [HAOI2015]树上操作 (树链剖分)
- 【BZOJ】4034 [HAOI2015]树上操作 树链剖分
- BZOJ 4034 [HAOI2015]树上操作 树链剖分
- bzoj 4034: [HAOI2015]树上操作 树链剖分
- BZOJ 4034 [HAOI2015]树上操作
- bzoj 4034 [HAOI2015]树上操作
- 【BZOJ 4034】 [HAOI2015]树上操作
- BZOJ 4034: [HAOI2015]树上操作
- bzoj 4034 [HAOI2015]树上操作
- BZOJ 4034 [HAOI2015]树上操作
- |BZOJ 4034|树链剖分|线段树|[HAOI2015]树上操作
- BZOJ[4034][HAOI2015]树上操作 树链剖分+线段树
- BZOJ 4034: [HAOI2015]树上操作【树链剖分】【DFS序】
- BZOJ 4034 :[HAOI2015]树上操作 树链剖分裸题
- bzoj P4034 [HAOI2015]树上操作
- 4034: [HAOI2015]树上操作
- [HAOI2015]树上操作 -树链剖分
- 垃圾回收器如何工作?
- 抽象工厂模式
- HDU 2089 不要62(数位DP入门+模板)
- 书目:《黑客简史》
- Linux 美化
- [树链剖分]bzoj 4034—— [HAOI2015]树上操作
- ≪统计学习精要(The Elements of Statistical Learning)≫课堂笔记(四)
- MySql修改 表名
- (学习java)写一个完整的程序,实现随机生成20个元素的链表,快速查找中间结点的值并显示
- C语言 二级指针详解及示例代码
- 根据两个经纬度坐标计算两个坐标间的距离
- Lintcode148 Sort Colors solution 题解
- 08-面向对象(继承-Java中的单继承和多重继承). 11-面向对象(继承-子父类中成员变量的内存图解) 11-面向对象(继承-子父类中成员变量的内存图解2
- 可以用作javascript异步模式的编程的方法