传送门

这题大概就是传说中的动态树形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. (samba启动失败)smb.service: main process exited, code=exited, status=1/FAILURE

    按照指示,前往:journalctl -xe 没什么发现,搜的时候有人说也可以查看 journalctl -r 打出来之后我也看不出什么门道来 又看到有人说 smb 方面可以看看 testparm 我 ...

  2. 近期js

    1 var value1 = 0, value2 = 0, value3 = 0; for ( var i = 1; i <= 3; i++) { var i2 = i; (function() ...

  3. (2)Oracle基础--表空间

    · 表空间概述 <1> 理解表空间 ① 表空间与数据库的关系: 表空间是数据库的逻辑存储空间,可以理解为在数据库中开辟的一块空间,用于存放数据库的对象. 一个数据库可以由多个表空间构成.O ...

  4. Storm Trident API

    在Storm Trident中有五种操作类型 Apply Locally:本地操作,所有操作应用在本地节点数据上,不会产生网络传输 Repartitioning:数据流重定向,单纯的改变数据流向,不会 ...

  5. maven添加仓库没有的jar包

    mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc14 -Dversion=10.2.0.4.0 -Dpackaging= ...

  6. 【wireshark】开发环境搭建

    1. 引言 本文相关内容可参考Wireshark开发指南第2章”Quick Setup” 要对wireshark代码进行修改,除了下文介绍的lua插件的方式以外,都需要对wirehshark源码进行编 ...

  7. ReentrantLock总体概括

    一.锁的实现原理: JAVA concurrent包下面的锁是通过AbstractQueuedSynchronizer内的Node类下面的state属性来实现的,并且锁的可重入属性也是通过state实 ...

  8. 移动端页面模板viewport

    <!DOCTYPE html><html> <head> <meta charset="utf-8" /> <meta nam ...

  9. deepin安装Mariadb后,登录时出现ERROR 1045 (28000): Access denied for user 'root'@'localhost'

    安装Mariadb的时候设置了root密码,但是登录的时候出现了这样的提示 这里记录下我的处理方法.我是用的如果重置root密码的套路. 首先,在/etc/mysql/mariadb.conf.d/5 ...

  10. linux解压.tar.xz压缩包

    今天,打算更新一下node版本(v6.11.1 -> v8.9.4),结果阿里云服务器使用nvm命令下载慢如牛,于是直接在node官网找到合适的v8.9.4压缩包下载到电脑里,然后up到阿里云服 ...