【BZOJ5210】最大连通子块和

Description

给出一棵n个点、以1为根的有根树,点有点权。要求支持如下两种操作:
M x y:将点x的点权改为y;
Q x:求以x为根的子树的最大连通子块和。
其中,一棵子树的最大连通子块和指的是:该子树所有子连通块的点权和中的最大值
(本题中子连通块包括空连通块,点权和为0)。

Input

第一行两个整数n、m,表示树的点数以及操作的数目。
第二行n个整数,第i个整数w_i表示第i个点的点权。
接下来的n-1行,每行两个整数x、y,表示x和y之间有一条边相连。
接下来的m行,每行输入一个操作,含义如题目所述。保证操作为M x y或Q x之一。
1≤n,m≤200000 ,任意时刻 |w_i|≤10^9 。

Output

对于每个Q操作输出一行一个整数,表示询问子树的最大连通子块和。

Sample Input

5 4
3 -2 0 3 -1
1 2
1 3
4 2
2 5
Q 1
M 4 1
Q 1
Q 2

Sample Output

4
3
1

题解:首先思路源自WC2018上陈俊锟所说的动态DP。

$O(n^2)$做法:

我们考虑每次询问时都进行一次树形DP。我们令f[x]表示x子树中,包含x的连通块的权值和最大值(可以为空),容易得到DP方程:$f[x]=max(0,v[x]+\sum f[y])$(y是x的儿子)。再维护s[x]表示x的子树中连通块的权值和最大值,$s[x]=max(f[x],s[y]) $。如果每次询问都进行一次树形DP的话,修改的复杂度是O(1),查询的复杂度是O(x的子树大小)。但是我们发现每次修改时只会对x到根这一条链上的点的DP值造成影响,其中对f[]的影响可以直接加减得到,对s[]的影响我们可以通过对每个点都开一个可删除堆维护。这样一来查询的复杂就变成了O(1),但是修改的复杂度变成了O(x的深度*log n),依然无法通过此题。

$O(n\log^2n)$做法:

我们考虑优化上面说的第二种暴力,不难想到用树剖+线段树来维护。我们令$g[x]=\sum f[y] $(y是x的轻儿子)。那么重链上的转移就变成了$f[x]=max(0,f[son[x]]+g[x])$。你会惊讶的发现这个式子就是最大连续子段和的形式!所以在修改时,我们从x沿着不断往根跳,对于重链,在线段树上维护g[x]的最大连续子段和;对于轻链,暴力维护DP值即可。

接下来考虑如何维护s[]。我们沿用上面的思路,对每个点维护一个可删除堆,但是这里的堆维护的是x的所有轻儿子的s值,重儿子的s值我们放到线段树上同最大连续子段和一起维护(代码中记为sm,表示max(g值的最大连续子段和,所有点的轻儿子的s))。那么我们在线段树上更新时,只需要用堆顶的元素来更新最大连续子段和,便完成了s[x]从底往上的传递。

在查询时,我们只需要将 x所在链的链底—x 在线段树上对应的区间 的最大连续子段和取出来即可。

这样一次修改的复杂度是$O(log^2n)$的,一次询问的复杂度是$O(\log n)$的。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=200010;
typedef long long ll;
int n,m,cnt;
int to[maxn<<1],next[maxn<<1],head[maxn],p[maxn],q[maxn],siz[maxn],dep[maxn],fa[maxn],top[maxn],son[maxn],sson[maxn];
ll v[maxn],f[maxn],g[maxn],ms[maxn];
char str[5];
struct heap
{
priority_queue<ll> p1,p2;
inline void push(ll x) {p1.push(x);}
inline void erase(ll x) {p2.push(x);}
inline ll top()
{
while(!p2.empty()&&p1.top()==p2.top()) p1.pop(),p2.pop();
if(p1.empty()) return 0;
return p1.top();
}
}mx[maxn];
struct sag
{
ll sl,sr,sm,s;
sag () {}
sag operator + (const sag &a) const
{
sag b;
b.s=s+a.s;
b.sl=max(sl,s+a.sl);
b.sr=max(a.sr,sr+a.s);
b.sm=max(sr+a.sl,max(sm,a.sm));
return b;
}
}s[maxn<<2];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
void dfs1(int x)
{
siz[x]=1;
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[x])
{
fa[to[i]]=x,dep[to[i]]=dep[x]+1,dfs1(to[i]),siz[x]+=siz[to[i]];
if(siz[to[i]]>siz[son[x]]) son[x]=to[i];
}
}
void dfs2(int x,int tp)
{
top[x]=tp,p[x]=++q[0],q[q[0]]=x;
if(son[x]) dfs2(son[x],tp),sson[x]=sson[son[x]],ms[x]=ms[son[x]];
else sson[x]=x;
g[x]=v[x];
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[x]&&to[i]!=son[x])
dfs2(to[i],to[i]),g[x]+=f[to[i]],mx[x].push(ms[to[i]]);
f[x]=max(0ll,g[x]+f[son[x]]),ms[x]=max(ms[x],f[x]),ms[x]=max(ms[x],mx[x].top());
}
void build(int l,int r,int x)
{
if(l==r)
{
s[x].s=g[q[l]];
s[x].sl=s[x].sr=max(g[q[l]],0ll);
s[x].sm=max(g[q[l]],mx[q[l]].top());
return ;
}
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
s[x]=s[lson]+s[rson];
}
void updata(int l,int r,int x,int a)
{
if(l==r)
{
s[x].s=g[q[l]];
s[x].sl=s[x].sr=max(g[q[l]],0ll);
s[x].sm=max(g[q[l]],mx[q[l]].top());
return ;
}
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,lson,a);
else updata(mid+1,r,rson,a);
s[x]=s[lson]+s[rson];
}
sag query(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b) return s[x];
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,lson,a,b);
if(a>mid) return query(mid+1,r,rson,a,b);
return query(l,mid,lson,a,b)+query(mid+1,r,rson,a,b);
}
inline void modify(int x,ll y)
{
sag t1,t2,t3;
int flag=0;
while(x)
{
t3=query(1,n,1,p[top[x]],p[sson[top[x]]]);
if(flag) mx[x].erase(t1.sm),mx[x].push(t2.sm);
t1=t3;
flag=1;
g[x]+=y,updata(1,n,1,p[x]);
t2=query(1,n,1,p[top[x]],p[sson[top[x]]]);
y=t2.sl-f[top[x]],f[top[x]]=t2.sl;
x=fa[top[x]];
}
}
inline void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
int main()
{
//freopen("A.in","r",stdin);
//freopen("A.out","w",stdout);
n=rd(),m=rd();
int i,a,b;
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++) v[i]=rd();
for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a);
dep[1]=1,dfs1(1),dfs2(1,1);
build(1,n,1);
for(i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='M')
{
a=rd(),b=rd();
modify(a,b-v[a]),v[a]=b;
}
else
{
a=rd();
printf("%lld\n",query(1,n,1,p[a],p[sson[a]]).sm);
}
}
return 0;
}//5 3 1 2 -3 -4 5 1 2 2 3 3 4 4 5 Q 2 C 4 1 Q 2

【BZOJ5210】最大连通子块和 树剖线段树+动态DP的更多相关文章

  1. BZOJ_2238_Mst_树剖+线段树

    BZOJ_2238_Mst_树剖+线段树 Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影 ...

  2. LUOGU P1967 货车运输(最大生成树+树剖+线段树)

    传送门 解题思路 货车所走的路径一定是最大生成树上的路径,所以先跑一个最大生成树,之后就是求一条路径上的最小值,用树剖+线段树,注意图可能不连通.将边权下放到点权上,但x,y路径上的lca的答案不能算 ...

  3. BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树

    BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...

  4. BZOJ_2157_旅游_树剖+线段树

    BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...

  5. [LNOI2014]LCA(树剖+线段树)

    \(\%\%\% Fading\) 此题是他第一道黑题(我的第一道黑题是蒲公英) 一直不敢开,后来发现是差分一下,将询问离线,树剖+线段树维护即可 \(Code\ Below:\) #include ...

  6. [CF1007D]Ants[2-SAT+树剖+线段树优化建图]

    题意 我们用路径 \((u, v)\) 表示一棵树上从结点 \(u\) 到结点 \(v\) 的最短路径. 给定一棵由 \(n\) 个结点构成的树.你需要用 \(m\) 种不同的颜色为这棵树的树边染色, ...

  7. LOJ#3088. 「GXOI / GZOI2019」旧词(树剖+线段树)

    题面 传送门 题解 先考虑\(k=1\)的情况,我们可以离线处理,从小到大对于每一个\(i\),令\(1\)到\(i\)的路径上每个节点权值增加\(1\),然后对于所有\(x=i\)的询问查一下\(y ...

  8. BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)

    传送门 完了今天才知道原来线段树的动态开点和主席树是不一样的啊 我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和 然后有了宗教信仰的限制该怎么做呢? 先考虑暴力 ...

  9. 【bzoj4699】树上的最短路(树剖+线段树优化建图)

    题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...

随机推荐

  1. VMware DHCP Service服务无法启动问题的解决

    我的电脑出现VMware DHCP Service和VMware NAT Service两个服务无法启动的问题: 打开VMware主界面,菜单->编辑->虚拟网络编辑器: 勾选上“将主机虚 ...

  2. JNI学习小结

    Java中类型与C/C++中对应关系   Java中的类的对应   Sign签名, 用来识别对应各个方法. JDK下的javap.exe能输出签名.用法javap -s -p 完整类名     下面是 ...

  3. 移除list中null元素

    查询结果为null, list.size()却是1 移除该null元素 totalList.removeAll(Collections.singleton(null));

  4. 绝对精品推荐做前端的看下:Web前端开发体会十日谈

    20151208感悟: 前端人的角度来看的话,感觉像是阅读一个大牛前端的全部武功的一个秘籍说明,里面的思想高价值蛋白真是太多太多,推荐看. Web前端开发体会十日谈 一直想写这篇“十日谈”,聊聊我对W ...

  5. JDK自带JVM性能调优监控工具jps、jstack、jmap、jhat、jstat

    原文地址:https://www.jianshu.com/p/db954cb968fb JVM性能调优监控工具jps.jstack.jmap.jhat.jstat位于JDK的bin目录,这些工具短小精 ...

  6. 在代码中设置RelativeLayout布局中标签的android:layout_toLeftOf、android:layout_toRightOf等属性

    需要动态改变RelativeLayout里面控件的相对位置,经一个技术群的群友提示,找到了如下的方法,做下记录:   RelativeLayout.Layoutparams params = (Rel ...

  7. [转]MySql 5.7关键字和保留字-附表

    原文地址:https://www.cnblogs.com/Z-Fanghan/p/6892944.html 现在使用navicat图形界面或者Hibernate做映射生成表的时候,渐渐的会忽视掉关键字 ...

  8. Java编程的逻辑 (85) - 注解

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...

  9. ffmpeg 移植到 android 并使用

    同步更新至个人blog:http://dxjia.cn/2015/07/ffmpeg-porting-to-android/ 空闲做了个小应用,从视频里截图,然后再将截图拼接为一个gif动画: 起初使 ...

  10. C++ 智能指针六

    /* 智能指针unique_ptr */ #include <iostream> #include <string> #include <memory> #incl ...