题目描述

  给你一棵\(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. .call() 和 .apply() 的含义和区别

    JavaScript中apply与call的用法意义及区别 apply()与call()的区别 javascript中apply和call方法的作用及区别说明 .apply()用法和call()的区别 ...

  2. Linux下查看文件系统磁盘使用

    [root@localhost ~]# df -h 可以查看所有文件系统的磁盘使用情况 du --max-depth=1 -h 可以查看当前目录下各子目录的磁盘使用情况 参考:http://www.2 ...

  3. Vue之子组件

    全局组件 <script src="./static/vue.min.js"></script> // 导入vue <body> <div ...

  4. Tomcat Cluster

    Tomcat群集配置| Tomcat集群| MuleSofthttps://www.mulesoft.com/tcat/tomcat-cluster Tomcat Clustering - A Ste ...

  5. 开发神器之phpstorm破解与日常使用

    PhpStorm 是 JetBrains 公司开发的一款商业的 PHP 集成开发工具,旨在提高用户效率,可深刻理解用户的编码,提供智能代码补全,快速导航以及即时错误检查. PhpStorm可随时帮助用 ...

  6. 了解真实的rem手机屏幕适配

    rem 作为一个低调的长度单位,由于手机端网页的兴起,在屏幕适配中得到重用.使用 rem 前端开发者可以很方便的在各种屏幕尺寸下,通过等比缩放的方式达到设计图要求的效果. rem 的官方定义『The ...

  7. 数据处理 array json 格式 转换成 数组形式

    处理这种数据应该使用的方式是 this.cities= res.data.data.cities.sort((a,b)=>{ //排序 进行字母排序 return a.pinyin[0].cha ...

  8. checkbox保存和赋值

    //货物信息中的表格内容 $.each(trG.find('td input,td select'),function(i,inp){ if($(inp).attr('type')=='checkbo ...

  9. python爬虫之Gerapy安装部署

    原创北航大才:https://cuiqingcai.com/5006.html NULL:http://www.infosec-wiki.com/?p=432737

  10. mysql逻辑架构

    逻辑架构图 MySQL有点与众不同,它的逻辑架构可以在多种不同的场景中应用并发挥良好的作用.主要体现在存储引擎的架构上,插件式的存储引擎架构将查询处理和其他的系统任务以及数据的存储提取相分离.这种架构 ...