传送门

这题大概就是传说中的动态树形DP了吧,学习了一波……

首先,对于没有修改的情况,不难想到树形DP,定义$f_i$表示强制必须选$i$且只能再选$i$的子树中的点的最优解,易得转移方程$f_i=\sum_{j是i的儿子}\max\{f_j,0\}+w_i$,最终答案即为$\max\{f_i\}$。

现在我们不仅需要求出答案,还要在每次修改之后快速计算新的答案。借鉴陈俊锟的论文,可以用树剖来做这道题,那么我们只需要对每条链动态维护答案即可,最后用一个全局堆维护每条链的答案就可以了。

我们可以重新定义$f_i$表示只考虑$i$以及轻边连出去的子树的最优解,并用线段树维护重链,不难看出每条链的答案就是链上所有点的$f$值的最大子段和。那么直接用线段树维护最大子段和即可,预处理$O(n)$,单次修改$O(\log^2 n)$,查询$O(1)$。

细节不是很多,当然愿意看代码也行。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn=;
struct binary_heap{
priority_queue<int>q1,q2;
binary_heap(){}
void push(int x){q1.push(x);}
void erase(int x){q2.push(x);}
int top(){
while(!q2.empty()&&q1.top()==q2.top()){
q1.pop();
q2.pop();
}
return q1.top();
}
}heap;
void dfs1(int);
void dfs2(int);
void modify(int,int);
void build(int,int,int&);
void modify(int,int,int);
void refresh(int);
vector<int>G[maxn];
int sum[maxn<<],maxsum[maxn<<],prefix[maxn<<],suffix[maxn<<],lc[maxn<<],rc[maxn<<],root[maxn],cnt=;
int p[maxn],size[maxn],d[maxn],dfn[maxn],finish[maxn],tim=,son[maxn],top[maxn],len[maxn];
int f[maxn],a[maxn],w[maxn];
int n,m,t,k;
int main(){
freopen("nortree.in","r",stdin);
freopen("nortree.out","w",stdout);
int __size__=<<;
char *__p__=(char*)malloc(__size__)+__size__;
__asm__("movl %0, %%esp\n"::"r"(__p__));
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%d",&w[i]);
for(int i=,x,y;i<n;i++){
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs1();
dfs2();
while(m--){
int d;
scanf("%d",&d);
if(d==){
int x,z;
scanf("%d%d",&x,&z);
modify(x,z);
}
else printf("%d\n",heap.top());
}
return ;
}
void dfs1(int x){
size[x]=;
d[x]=d[p[x]]+;
for(int i=;i<(int)G[x].size();i++)if(G[x][i]!=p[x]){
p[G[x][i]]=x;
dfs1(G[x][i]);
size[x]+=size[G[x][i]];
if(size[G[x][i]]>size[son[x]])son[x]=G[x][i];
}
}
void dfs2(int x){
if(x==son[p[x]])top[x]=top[p[x]];
else top[x]=x;
dfn[x]=++tim;
f[x]=w[x];
if(son[x])dfs2(son[x]);
for(int i=;i<(int)G[x].size();i++)if(G[x][i]!=p[x]&&G[x][i]!=son[x]){
dfs2(G[x][i]);
f[x]+=max(prefix[root[G[x][i]]],);
}
finish[x]=tim;
if(top[x]==x){
int cnt=,y=x;
while(y){
a[++cnt]=f[y];
y=son[y];
}
len[x]=cnt;
build(,len[x],root[x]);
heap.push(maxsum[root[x]]);
}
}
void modify(int x,int z){
f[x]+=z-w[x];
w[x]=z;
while(x){
if(p[top[x]])f[p[top[x]]]-=prefix[root[top[x]]];
heap.erase(maxsum[root[top[x]]]);
t=d[x]-d[top[x]]+;
k=f[x];
modify(,len[top[x]],root[top[x]]);
if(p[top[x]])f[p[top[x]]]+=prefix[root[top[x]]];
heap.push(maxsum[root[top[x]]]);
x=p[top[x]];
}
}
void build(int l,int r,int &rt){
rt=++cnt;
if(l==r){
sum[rt]=a[l];
maxsum[rt]=prefix[rt]=suffix[rt]=max(a[l],);
return;
}
int mid=(l+r)>>;
build(l,mid,lc[rt]);
build(mid+,r,rc[rt]);
refresh(rt);
}
void modify(int l,int r,int rt){
if(l==r){
sum[rt]=k;
maxsum[rt]=prefix[rt]=suffix[rt]=max(k,);
return;
}
int mid=(l+r)>>;
if(t<=mid)modify(l,mid,lc[rt]);
else modify(mid+,r,rc[rt]);
refresh(rt);
}
void refresh(int rt){
sum[rt]=sum[lc[rt]]+sum[rc[rt]];
maxsum[rt]=max(max(maxsum[lc[rt]],maxsum[rc[rt]]),suffix[lc[rt]]+prefix[rc[rt]]);
prefix[rt]=max(prefix[lc[rt]],sum[lc[rt]]+prefix[rc[rt]]);
suffix[rt]=max(suffix[rc[rt]],sum[rc[rt]]+suffix[lc[rt]]);
}

COGS2608 [河南省队2016]无根树的更多相关文章

  1. 【COGS 1534】 [NEERC 2004]K小数 &&【COGS 930】 [河南省队2012] 找第k小的数 可持久化01Trie

    板子题,只是记得负数加fix最方便 #include <cstdio> ,N=; namespace FIFO { <<],*S=B,*T=B; #define getc() ...

  2. 河南省队选拔 HAOI2015 解题报告

      其实省选在四天前就已经结束了,但由于题目难度略大我到今天上午才补完所有题目……(捂脸逃)考场上很幸运,打完了所有我会写的部分分,最后Round1的110分 + Round2的70分,勉强算是没有被 ...

  3. COGS 930. [河南省队2012] 找第k小的数 主席树

    主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 ...

  4. COGS 930. [河南省队2012] 找第k小的数

    题目描述 看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2,A3,...,AN, 现在有M个询问,每个询问都是Ai...Aj中第k小的数等于多少. 输入格式 第一行两个正整数N,M. ...

  5. [河南省队2012] 找第k小的数

    ★★☆   输入文件:kth.in   输出文件:kth.out   简单对比时间限制:1 s   内存限制:128 MB 题目描述 看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2 ...

  6. 数论知识总结——史诗大作(这是一个flag)

    1.快速幂 计算a^b的快速算法,例如,3^5,我们把5写成二进制101,3^5=3^1*1+3^2*2+3^4*1 ll fast(ll a,ll b){ll ans=;,a=mul(a,a)))a ...

  7. ACM入门记

    [2015.12]零基础进队 [2016.4.10]浙大第十六届程序设计大赛 [2016.6.4]团体程序设计天梯赛初赛 [2016.7.16]团体程序设计天梯赛决赛 赛后总结:比赛的时候好慌,一道题 ...

  8. 他是 ISIJ 第四名,也是在线知名题库的洛谷“网红”

    转载自加藤惠. 2020年国际初中生信息学竞赛(ISIJ)上,以优秀成绩拿下第四名年仅初三的张湫阳,成为最夺目的选手之一. 而且虽然是初三的选手,但他取得优异成绩后,不少网友并不感到陌生,纷纷留言: ...

  9. HNOI 2016 省队集训日记

    第一天 DeepDarkFantasy 从东京出发,不久便到一处驿站,写道:日暮里.  ——鲁迅<藤野先生> 定义一个置换的平方为对1~n的序列做两次该置换得到的序列.已知一个置换的平方, ...

随机推荐

  1. webpack快速入门——CSS中的图片处理

    1.首先在网上随便找一张图片,在src下新建images文件夹,将图片放在文件夹内 2.在index.html中写入代码:<div id="pic"></div& ...

  2. SnapKit 约束创建过程

     创建ConstraintViewDSL 调用UIView 的 snp 方法,生成一个ConstraintViewDSL. 注意这个生成的ConstraintViewDSL持有UIView. 创建C ...

  3. 转的很好的前端html 内容

    HTML 初识 web服务本质 import socket def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s ...

  4. python学习笔记02-编码

    ASCII码  255个  每一个占1个字节 8位 解决中文的问题:出现一张扩展表  支持中文的第一张表  gb2312  后来发展为GBK1.0 Gb18030 万国码:unicode 世界统一 存 ...

  5. 【OpenCV3】threshold()函数详解

    threshold()函数源码 double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double maxva ...

  6. .gitignore中添加的某个忽略文件并不生效

    最近项目中,来了一新同事,协同开发的过程中,发现老是提示pod install,于是照做了,做完项目可以跑成功但发现提示我跟同事一样的问题,Podfile.lock文件需要提交,于是便提交了,然而同事 ...

  7. jade直接写类似JavaScript语法的东西,不需要写script

    我们知道,html做计算都是在JavaScript中完成的,那么不用JavaScript行不行呢,可以直接在jade中一样的编写 如: -var a = 3 -var b = 4 div a+b = ...

  8. 02--STL算法(函数对象和谓词)

    一:函数对象(仿函数):实现状态记录等其他操作<相对于普通函数> 重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象. 即是重载了“ ...

  9. scala combineByKey用法说明

    语法是: combineByKey[C](   createCombiner: V => C,   mergeValue: (C, V) => C,   mergeCombiners: ( ...

  10. Postman—命令执行脚本及生成报告

    前言 前面的应用中,都是在postman图形界面工具里面进行测试,但是有时候我们需要把测试脚本集成到CI平台,或者在非图形界面的系统环境下进行测试,那么我们该如果处理呢 通过newman来执行post ...