[xsy1294]sub
给出一棵$N$个节点的无根树,节点$i$有权值$v_i$。现在有$M$次操作,操作有如下两种:
$1\ x\ y$ 将节点$x$的权值$v_x$修改为$y$
$2$ 选择一个联通块(也可以不选择),使得点权和最大。输出这个点权和
树剖==
考虑先做一次DP,$f_x$表示在以$x$为根的子树中,选择$x$的情况下的最大联通块和,那么$f_x=v_x+\sum\limits_{u\in son_x}\max(f_u,0)$($v_x$表示点$x$的权值)
然后树剖,每一个点的权值设为$f_x-f_{heavy_x}$($heavy_x$表示点$x$的重儿子),然后可以发现,对于一条重链所代表的区间,求最大子段和就是这条链上所有点的最大答案
为了避免不同重链之间互相影响,我们可以在重链之间加上一个空节点,权值为$-\infty$
考虑修改,修改一个点只会影响它沿重链往上跳时经过的(重链顶端节点的父亲节点),所以我们只需要修改重链顶端的父亲节点就好了
#include<stdio.h> typedef long long ll; const ll inf=1000000000ll; ll max(ll a,ll b){return a>b?a:b;} struct zt{ ll s,ms,ls,rs; }f[400010]; zt merge(zt l,zt r){ zt c; c.s=l.s+r.s; c.ls=max(l.ls,l.s+r.ls); c.rs=max(r.rs,r.s+l.rs); c.ms=max(max(l.ms,r.ms),l.rs+r.ls); return c; } void pushup(int x){f[x]=merge(f[x<<1],f[x<<1|1]);} ll p[200010]; void build(int l,int r,int x){ if(l==r){ f[x].s=p[l]; f[x].ms=f[x].ls=f[x].rs=max(p[l],0); return; } int mid=(l+r)>>1; build(l,mid,x<<1); build(mid+1,r,x<<1|1); pushup(x); } void modify(int p,ll v,int l,int r,int x){ if(l==r){ f[x].s+=v; f[x].ms=f[x].ls=f[x].rs=max(f[x].s,0); return; } int mid=(l+r)>>1; if(p<=mid) modify(p,v,l,mid,x<<1); else modify(p,v,mid+1,r,x<<1|1); pushup(x); } zt query(int L,int R,int l,int r,int x){ if(L<=l&&r<=R)return f[x]; int mid=(l+r)>>1; if(R<=mid)return query(L,R,l,mid,x<<1); if(L>mid)return query(L,R,mid+1,r,x<<1|1); return merge(query(L,R,l,mid,x<<1),query(L,R,mid+1,r,x<<1|1)); } int h[100010],nex[200010],to[200010],v[100010],fa[100010],siz[100010],son[100010],bl[100010],pos[100010],M; ll dp[100010]; void add(int a,int b){ M++; to[M]=b; nex[M]=h[a]; h[a]=M; } void dfs(int x){ int i,mx=0,k=0; siz[x]=1; dp[x]=v[x]; for(i=h[x];i;i=nex[i]){ if(to[i]!=fa[x]){ fa[to[i]]=x; dfs(to[i]); dp[x]+=max(dp[to[i]],0); siz[x]+=siz[to[i]]; if(siz[to[i]]>mx){ mx=siz[to[i]]; k=to[i]; } } } son[x]=k; } void dfs(int x,int chain){ pos[x]=++M; bl[x]=chain; if(son[x]){ dp[x]-=max(dp[son[x]],0); dfs(son[x],chain); } p[pos[x]]=dp[x]; for(int i=h[x];i;i=nex[i]){ if(to[i]!=fa[x]&&to[i]!=son[x]){ M++; p[M]=-inf; dfs(to[i],to[i]); } } } void modify(int x,ll d){ d-=v[x]; v[x]+=d; ll t1,t2; while(x){ t1=query(pos[bl[x]],M,1,M,1).ls; modify(pos[x],d,1,M,1); t2=query(pos[bl[x]],M,1,M,1).ls; d=t2-t1; x=fa[bl[x]]; } } int main(){ int n,m,i,x,y; scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%d",v+i); for(i=1;i<n;i++){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1); M=0; dfs(1,1); build(1,M,1); while(m--){ scanf("%d",&i); if(i==1){ scanf("%d%d",&x,&y); modify(x,y); }else printf("%d\n",f[1].ms); } }
[xsy1294]sub的更多相关文章
- 【XSY1294】sub 树链剖分
题目描述 给你一棵\(n\)个点的无根树,节点\(i\)有权值\(v_i\).现在有\(m\)次操作,操作有如下两种: \(1~x~y\):把\(v_x\)改成\(y\). \(2\):选择一个连通块 ...
随机推荐
- HZOI String STL的正确用法
String 3s 512 MB描述硬盘中里面有n ...
- 自定义toolbar教程
1.写toolbar的布局文件 ,toolbar.xml <?xml version="1.0" encoding="utf-8"?> <Re ...
- keydown
<!DOCTYPE HTML><html><head> <meta charset="utf-8"> <title>无标 ...
- 纯手工 CheckboxTree 实现
数据结构及页面显示格式: INSERT INTO AS_CombRules VALUES('', '', '', '', '', '', '') 实现 CheckboxTree 功能: html代码: ...
- ios上传图片显示方向错误问题
IOS 上传图片方向显示错误问题 问题描述 在使用苹果手机上传图片的时候,发现传完的图片显示出来方向是错误的,竖着的图片会变成横着显示(少部分安卓手机也存在这个问题) 产生原因 ios 相机加入了方向 ...
- 网络编程:connect函数
TCP客户用connect函数来建立与TCP服务器的连接: cpp #include<sys/socket.h> int connect(int sockfd, const struct ...
- 栈的图文解析 和 对应3种语言的实现(C/C++/Java)【转】
概要 本章会先对栈的原理进行介绍,然后分别通过C/C++/Java三种语言来演示栈的实现示例.注意:本文所说的栈是数据结构中的栈,而不是内存模型中栈.内容包括:1. 栈的介绍2. 栈的C实现3. 栈的 ...
- 会议中心[APIO2009]
会议中心 思路 这一题的正解是倍增的,但是由于我太蒟蒻了,所以我选了一个不算正解但是有可以拿满分的题目学习 思路和我考场上其实差不多,只是我无法实现.... 下面我先来介绍几个数组的用途 1.s,s数 ...
- [bzoj1208][HNOI2004]宠物收养所——splay
题目大意 Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发 ...
- 常见的makefile写法【转】
转自:http://blog.csdn.net/ghostyu/article/details/7755177 版权声明:本文为博主原创文章,未经博主允许不得转载. .目标名称,摆脱手动设置目标名称 ...