题目描述

  给你一棵\(n\)个点的无根树,节点\(i\)有权值\(v_i\)。现在有\(m\)次操作,操作有如下两种:

   \(1~x~y\):把\(v_x\)改成\(y\)。

   \(2\):选择一个连通块(也可以不选择),使得点权和最大。输出这个点权和。

  \(n,m\leq {10}^5,|v_i|,|y|\leq 1000\)

题解

  考虑暴力,\(dp_x=v_x+\sum_{y\text{是}x\text{的儿子}}\max(dp_y,0)\)

  还记得如果是一条链的问题要怎么做吗?没错,就是线段树。每个区间维护四个信息:

   sum表示整个区间的权值和

   ls表示以从左边界往右的连续段最大权值和

   rs表示以从右边界往左的连续段最大权值和

   s表示整个区间中连续段最大权值和

  现在这是一棵树,也可以用类似的方法处理。

  对于一条重链,每个点的权值就是这个点的\(v\)值加上轻儿子的\(dp\)值。那么这条链的答案就是线段树对应区间的连续段最大权值和。

  

  修改权值的时候,这条链对这条链顶部的轻链上方那个节点的贡献就是修改后从最上面往下的答案\(-\)修改前从最上面往下的答案。

  但是线段树上一个区间在原树上不一定是联通的。我们可以在两条不同的重链之间加一个点,权值为\(-\infty\)。这样所有的答案就不会跨过这个不存在的点了。

  时间复杂度:\(O(m\log^2 n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<list>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
ll dp[200010];
int c[200010];
namespace seg
{
struct pp
{
ll ls,rs,s,sum;
};
pp operator +(pp a,pp b)
{
pp c;
c.sum=a.sum+b.sum;
c.ls=max(a.ls,a.sum+b.ls);
c.rs=max(b.rs,b.sum+a.rs);
c.s=max(max(a.s,b.s),a.rs+b.ls);
return c;
}
pp s[500010];
int ls[500010];
int rs[500010];
int cnt;
int build(int l,int r)
{
int p=++cnt;
if(l==r)
{
s[p].sum=c[l];
s[p].ls=s[p].rs=s[p].s=max(0ll,s[p].sum);
return p;
}
int mid=(l+r)>>1;
ls[p]=build(l,mid);
rs[p]=build(mid+1,r);
s[p]=s[ls[p]]+s[rs[p]];
return p;
}
void change(int p,int x,ll v,int L,int R)
{
if(L==R)
{
s[p].sum+=v;
s[p].ls=s[p].rs=s[p].s=max(0ll,s[p].sum);
return;
}
int mid=(L+R)>>1;
if(x<=mid)
change(ls[p],x,v,L,mid);
else
change(rs[p],x,v,mid+1,R);
s[p]=s[ls[p]]+s[rs[p]];
}
pp query(int p,int l,int r,int L,int R)
{
if(l<=L&&r>=R)
return s[p];
int mid=(L+R)>>1;
if(r<=mid)
return query(ls[p],l,r,L,mid);
if(l>mid)
return query(rs[p],l,r,mid+1,R);
return query(ls[p],l,r,L,mid)+query(rs[p],l,r,mid+1,R);
}
};
struct p
{
int s,ms,f,d,t,w;
};
int inf=0x7fffffff;
p a[100010];
list<int> l[100010];
int v[100010];
int ti;
void dfs(int x,int f,int d)
{
a[x].f=f;
a[x].d=d;
a[x].s=1;
dp[x]=v[x];
int sz=0;
for(auto v:l[x])
if(v!=f)
{
dfs(v,x,d+1);
dp[x]+=max(dp[v],0ll);
a[x].s+=a[v].s;
if(a[v].s>sz)
{
sz=a[v].s;
a[x].ms=v;
}
}
}
void dfs2(int x,int t)
{
a[x].t=t;
a[x].w=++ti;
if(a[x].ms)
{
dp[x]-=max(dp[a[x].ms],0ll);
dfs2(a[x].ms,t);
for(auto v:l[x])
if(v!=a[x].f&&v!=a[x].ms)
{
c[++ti]=-inf;
dfs2(v,v);
}
}
c[a[x].w]=dp[x];
}
void change(int x,int y)
{
y-=v[x];
v[x]+=y;
for(;x;x=a[a[x].t].f)
{
int t=a[a[x].t].w;
int v1=seg::query(1,t,ti,1,ti).ls;
seg::change(1,a[x].w,y,1,ti);
int v2=seg::query(1,t,ti,1,ti).ls;
y=v2-v1;
}
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
seg::cnt=0;
int n,m;
scanf("%d%d",&n,&m);
int i;
for(i=1;i<=n;i++)
scanf("%d",&v[i]);
int x,y;
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
l[x].push_back(y);
l[y].push_back(x);
}
ti=0;
dfs(1,0,1);
dfs2(1,1);
seg::build(1,ti);
for(i=1;i<=m;i++)
{
scanf("%d",&x);
if(x==1)
{
scanf("%d%d",&x,&y);
change(x,y);
}
else
printf("%lld\n",seg::s[1].s);
}
return 0;
}

【XSY1294】sub 树链剖分的更多相关文章

  1. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  2. BZOJ 1984: 月下“毛景树” [树链剖分 边权]

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1728  Solved: 531[Submit][Status][Discu ...

  3. codevs 1228 苹果树 树链剖分讲解

    题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...

  4. 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)

    题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...

  5. 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)

    题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...

  6. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  7. bzoj2243树链剖分+染色段数

    终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...

  8. bzoj3631树链剖分

    虽然是水题1A的感觉太爽了O(∩_∩)O~ 题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值 本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...

  9. BZOJ 3531: [Sdoi2014]旅行 [树链剖分]

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1685  Solved: 751[Submit][Status] ...

  10. BZOJ 2243: [SDOI2011]染色 [树链剖分]

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6651  Solved: 2432[Submit][Status ...

随机推荐

  1. 根据指定条件使CheckBox 无法选中

    var trList = $("#tab1").children("tr")for (var i=0;i<trList.length;i++) {var ...

  2. Full Regularization Path for Sparse Principal Component Analysis

    目录 背景 Notation Sparse PCA Semidefinite Relaxation Low Rank Optimization Sorting and Thresholding 背景 ...

  3. CodeForces 719A. Vitya in the Countryside

    链接:[http://codeforces.com/group/1EzrFFyOc0/contest/719/problem/A] 题意: 给你一个数列(0, 1, 2, 3, 4, 5, 6, 7, ...

  4. 关于对于system函数和c++标准下的新的变量定义方式{}

  5. R语言

    什么是R语言编程? R语言是一种用于统计分析和为此目的创建图形的编程语言.不是数据类型,它具有用于计算的数据对象.它用于数据挖掘,回归分析,概率估计等领域,使用其中可用的许多软件包. R语言中的不同数 ...

  6. 在Git中添加一个项目

    首先保证Git服务器正确配置,管理员机器可正常连接并使用Git. 第一步:在服务器上新建一个项目仓库 切换到git用户: a@ubuntu:/home/git$ su - git $ cd /home ...

  7. html总结:float实现span和input输入框同行

    例: <input type="text" name="ytdwname" value="<%=user.getYtdwname() %& ...

  8. PAT 7-14 公路村村通

    https://pintia.cn/problem-sets/1111189748004499456/problems/1111189831248850957 现有村落间道路的统计数据表中,列出了有可 ...

  9. Es5中的类和静态方法 继承

    Es5中的类和静态方法 继承(原型链继承.对象冒充继承.原型链+对象冒充组合继承) // es5里面的类 //1.最简单的类 // function Person(){ // this.name='张 ...

  10. IdentityServer4【Introduction】之术语

    术语 在规范.文档和对象模型中使用了一些你应该了解的术语. IdentityServer IdentityServer是一个OpenID Connect的提供者,它实现了OpenID Connect和 ...