[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\):选择一个连通块 ...
随机推荐
- Educational Codeforces Round 55 (Rated for Div. 2):D. Maximum Diameter Graph
D. Maximum Diameter Graph 题目链接:https://codeforces.com/contest/1082/problem/D 题意: 给出n个点的最大入度数,要求添加边构成 ...
- tyvj1305 最大子序和(单调队列
题目地址:http://www.joyoi.cn/problem/tyvj-1305 最大子序和 题目限制 时间限制 内存限制 评测方式 题目来源 1000ms 131072KiB 标准比较器 Loc ...
- C++ 中 string, char*, int 类型的相互转换
一.int 1.int 转换成 string 1) to_string函数 —— c++11标准增加了全局函数std::to_string: string to_string (int val); s ...
- PowerShell官方文档
PowerShell PowerShell 在 .NET Framework 基础之上构建,是一种基于任务的命令行 Shell 脚本语言:专门面向系统管理员和高级用户,可快速自动化多个操作系统(Lin ...
- 如何把SSL公钥和私钥转化为PFX格式
1.登陆 https://myssl.com/cert_convert.html 2.原格式选择为 “PEM”,目标格式选择为 “PKCS12” 3.上传cer到 ”证书文件“,上传key到 ”私 ...
- 深入探索 高效的Java异常处理框架
转载自:http://www.sunwei.org/archives/196 摘要:本文从Java异常最基本的概念.语法开始讲述了Java异常处理的基本知识,分析了Java异常体系结构,对比Sprin ...
- 'express' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
新安装了express,但是当查看版本号输入: express -v 时出现如下错误: 网上查找了相关资料才发现express查看版本 的命令是 express -V (即V大写) 再次尝试: 发现同 ...
- UOJ#80 二分图最大权匹配 [模板题]
从前一个和谐的班级,有 nlnl 个是男生,有 nrnr 个是女生.编号分别为 1,…,nl1,…,nl 和 1,…,nr1,…,nr. 有若干个这样的条件:第 vv 个男生和第 uu 个女生愿意结为 ...
- 微信小程序登录状态
我们知道,WEB服务器通过浏览器携带的cookie获取session来判断是否是同一用户(或浏览器):Restful服务通过客户端传过来唯一ID,来识别调用用户. >为什么需要维护登录态? 有自 ...
- docker push 镜像到本地仓库
root@ubuntu:# uname -a Linux ubuntu --generic #-Ubuntu SMP Mon Feb :: UTC x86_64 x86_64 x86_64 GNU/L ...