COGS2608 [河南省队2016]无根树
这题大概就是传说中的动态树形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]无根树的更多相关文章
- 【COGS 1534】 [NEERC 2004]K小数 &&【COGS 930】 [河南省队2012] 找第k小的数 可持久化01Trie
板子题,只是记得负数加fix最方便 #include <cstdio> ,N=; namespace FIFO { <<],*S=B,*T=B; #define getc() ...
- 河南省队选拔 HAOI2015 解题报告
其实省选在四天前就已经结束了,但由于题目难度略大我到今天上午才补完所有题目……(捂脸逃)考场上很幸运,打完了所有我会写的部分分,最后Round1的110分 + Round2的70分,勉强算是没有被 ...
- COGS 930. [河南省队2012] 找第k小的数 主席树
主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 ...
- COGS 930. [河南省队2012] 找第k小的数
题目描述 看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2,A3,...,AN, 现在有M个询问,每个询问都是Ai...Aj中第k小的数等于多少. 输入格式 第一行两个正整数N,M. ...
- [河南省队2012] 找第k小的数
★★☆ 输入文件:kth.in 输出文件:kth.out 简单对比时间限制:1 s 内存限制:128 MB 题目描述 看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2 ...
- 数论知识总结——史诗大作(这是一个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 ...
- ACM入门记
[2015.12]零基础进队 [2016.4.10]浙大第十六届程序设计大赛 [2016.6.4]团体程序设计天梯赛初赛 [2016.7.16]团体程序设计天梯赛决赛 赛后总结:比赛的时候好慌,一道题 ...
- 他是 ISIJ 第四名,也是在线知名题库的洛谷“网红”
转载自加藤惠. 2020年国际初中生信息学竞赛(ISIJ)上,以优秀成绩拿下第四名年仅初三的张湫阳,成为最夺目的选手之一. 而且虽然是初三的选手,但他取得优异成绩后,不少网友并不感到陌生,纷纷留言: ...
- HNOI 2016 省队集训日记
第一天 DeepDarkFantasy 从东京出发,不久便到一处驿站,写道:日暮里. ——鲁迅<藤野先生> 定义一个置换的平方为对1~n的序列做两次该置换得到的序列.已知一个置换的平方, ...
随机推荐
- Python-WSGI协议,mini-web框架
本次带给大家的是WSGI-mini-web框架, 其中要下载一些网络页面, 大佬们不要见怪. 我所做的mini-web 支持路由, 正则表达式, 添加了log日志功能:解析了url编码可以用 来理解W ...
- 读Lock-Free论文实践
论文地址:implementing Lock-Free Queue 论文大体讲的意思是:Lock-Base的程序的performance不好,并且a process inside the critic ...
- OC 中的属性
自动合成 (autosynthesis) @property 语法,会做下面两件事情 自动生成存取方法 由编译器生成,编辑器里不会看到这些方法. 向类中添加适当类型的实例变量 在属性前加下划线,作为实 ...
- iOS(Swift)-Runtime之关于页面跳转的捷径【Runtime获取当前ViewController,很常用】
写在前面 在我们操作页面跳转时,如果当前的类不是UIViewcontroller(下面用VC表示),你会不会写一个代理,或者block给VC传递信息,然后在VC里面进行 ///假如targetVc是将 ...
- js的let语句在安卓手机端的QQ浏览器出错的问题
关于JavaScript里面的let,let 语句可以声明一个块级作用域的本地变量,并且可选的将其初始化为一个值. <ul id="list"> </ul> ...
- 全屏背景图的实现及background的相关属性
今天需要做一个占满设备宽度的轮播图,这里作为demo仅展示一张图,下面分别是要操作的图片(这里做了缩放处理,实际的图比较大),以及要实现的效果图,很明显两者是不成比例的: (图一) ...
- java基本语法二
1 运算符 1.1 运算符的概念 运算符是一种特殊的符号,用以表示数据的运算.赋值和比较等. 在java语言中,运算符有如下的分类: ①算术运算符. ②赋值运算符. ③比较运算符(关系运算符). ④逻 ...
- 常用chrome插件&&常用FireFox插件
第一部分:chrome插件 chrome中输入 chrome://chrome-urls/ 可以得到包括缓存在内的很多相关信息. 1.掘金chrome插件 点击下载 掘金是一个高质量的互联网技术 ...
- Java之IO(零)总结
转载请注明原出处:http://www.cnblogs.com/lighten/p/7274378.html 1.前言 本章是对之前所讲述的整个Java的IO包的一个总结,抽出个人认为比较重要的知识点 ...
- java 中几种常用数据结构
Java中有几种常用的数据结构,主要分为Collection和map两个主要接口(接口只提供方法,并不提供实现),而程序中最终使用的数据结构是继承自这些接口的数据结构类. 一.几个常用类的区别 1.A ...