【XSY1294】sub 树链剖分
题目描述
给你一棵\(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 树链剖分的更多相关文章
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 1984: 月下“毛景树” [树链剖分 边权]
1984: 月下“毛景树” Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 1728 Solved: 531[Submit][Status][Discu ...
- codevs 1228 苹果树 树链剖分讲解
题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...
- 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)
题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...
- 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)
题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...
- 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)
题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...
- bzoj2243树链剖分+染色段数
终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...
- bzoj3631树链剖分
虽然是水题1A的感觉太爽了O(∩_∩)O~ 题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值 本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...
- BZOJ 3531: [Sdoi2014]旅行 [树链剖分]
3531: [Sdoi2014]旅行 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1685 Solved: 751[Submit][Status] ...
- BZOJ 2243: [SDOI2011]染色 [树链剖分]
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6651 Solved: 2432[Submit][Status ...
随机推荐
- elasticsearch简单操作(二)
让我们建立一个员工目录,假设我们刚好在Megacorp工作,这时人力资源部门出于某种目的需要让我们创建一个员工目录,这个目录用于促进人文关怀和用于实时协同工作,所以它有以下不同的需求:1.数据能够包含 ...
- linux-高并发与负载均衡-TCP-IP基础知识
ARP协议: ping baidu
- CF892/problem/C
题目传送门: [http://codeforces.com/contest/892/problem/C] 题意: 给你一个长度为n的数组,相邻两个元素的GCD(最大公约数)可以取代二者的任意一个,问你 ...
- jquery中ajax使用
JQuery的Ajax操作,对JavaScript底层Ajax操作进行了封装, <script type="text/javascript"> $.ajax({ url ...
- Git - 常见错误与解决方案
1.windows使用git时出现:warning: LF will be replaced by CRLF 分析: windows中的换行符为 CRLF, 而在linux下的换行符为LF,所以在执行 ...
- SQL性能优化-order by语句的优化
原文:http://bbs.landingbj.com/t-0-243203-1.html 在某些情况中,MySQL可以使用一个索引来满足ORDER BY子句,而不需要额外的排序.where条件和or ...
- 完美解决safari、微信浏览器下拉回弹效果
CSS代码: .box{ overflow: auto; -webkit-overflow-scrolling: touch; } HTML代码: <body class="box&q ...
- IdentityServer4【QuickStart】之使用ResourceOwnerPassword流程来保护API
使用ResourceOwnerPassword流程来保护API OAuth2.0中的ResourceOwnerPassword授权流程允许一个客户端发送username和password到token服 ...
- Oracle行列转换case when then方法案例
select (select name from t_area where id=areaid) 区域, end) 一月, end) 二月, end) 三月, end) 四月, end) 五月, en ...
- day 7-20 视图,触发器,事务
一.视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,可以将该结果集当做表来使用. 使用视图我们可以把查询过程中的 ...