传送门

这题大概就是传说中的动态树形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. ansible 的第一次亲密接触

    如何添加一台机器 编辑 /etc/ansible/hosts 添加本机的 public ssh key 到目标机器的 authorized_keys 添加本机的 私钥 到 ansible 运行 ans ...

  2. 【洛谷mNOIP模拟赛Day1】T1 斐波那契

    题目传送门:https://www.luogu.org/problemnew/show/P3938 这题出得特别吼啊~~ 通过打表或者大胆猜想斐波那契数列的一些性质,我们不难发现对于一只兔子$x$,其 ...

  3. LINUX下 一句话添加用户并设置ROOT权限

    来源:linux一条命令添加用户并设置密码 linux一条命令添加一个root级别账户并设置密码 LINUX提权,除非是拿的EXP反弹CMD,才会有回显,这样添加管理员方便了. 通常是在SHELL,菜 ...

  4. [笔记] Python 中JSON数据的读写

    前言 JSON(JavaScript Object Notation,JavaScript对象表示法)是一种轻量级的数据交换语言 JSON是独立于语言的文本格式, JSON 数据格式与语言无关 JSO ...

  5. 浏览器Request Header和Response Header的内容

    1)请求(客户端->服务端[request])     GET(请求的方式) /newcoder/hello.html(请求的目标资源) HTTP/1.1(请求采用的协议和版本号)     Ac ...

  6. 体验 QQ机器人C# SDK 1.X 特性总结

    主要特性 依赖注入 框架本身采用 Autofac 作为依赖注入框架.进行插件开发时,必然会使用到该框架.建议开发者阅读官方文档熟悉其用法.https://autofac.readthedocs.io/ ...

  7. golang基础--控制语句

    go基础之控制语句 补充知识 指针 与其他语言不同,在Go中不支持指针运算即->运算符,而直接采用.选择符来操作指针目标对象的成员. 操作符&取变量的地址,使用*通过指针间间接访问目标对 ...

  8. .Net调用Java端带有WS-Security支持的Web Service【亲测通过】

    做了几年的开发,今天终于鼓起勇气开通了博客园.平时都是找各种大牛,看他们的分享博客的解决BUG.从今天起,我也开始分享我学习之路.还望大家多多支持! 最近收到一个采用Axis2实现的WebServic ...

  9. c#基础学习(0806)之抽象类实现多态

    首先,要判断是否使用抽象类,可以从下面两个方面进行判断: 1.是不是需要被实例化 2.父类中有没有默认的实现 如果不需要被实例化,父类中没有默认的实现,则用抽象类(否则用虚方法来实现) 下面举个简单的 ...

  10. C学习笔记(1)-结构体、预处理与多文件结构程序设计

    一.结构体的定义与使用 #include <stdio.h> //定义结构体(类似模板) typedef struct { char name[50]; int age; char add ...