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的序列做两次该置换得到的序列.已知一个置换的平方, ...
随机推荐
- springboot入门之简单demo
项目构建 我们采用maven构建SpringBoot工程,首先创建一个maven工程,对应的pom文件如下: <properties> <java.version>1.8< ...
- SQL 必知必会 总结(一)
SQL必知必会 总结(一) 第 1 课 了解SQL 1.数据库(database): 保存有组织的数据容器(通常是一个文件或一组文件). 2.数据库管理系统(DBMS): 数据库软件,数据库是通过 D ...
- 《JAVA与模式》之建造模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal representation ...
- day 55 linux 的常用命令
前言 前面咱们已经成功安装了Linux系统--centos7,那么我们现在提好裤腰带,准备奔向Linux的大门. Linux命令行的组成结构 [root@oldboy_python ~]# [roo ...
- 快速排序的理解和实现(Java)
快速排序介绍 快速排序(Quick Sort)使用分治法策略,其基本思想是:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另外一部分记录的关键字小,则可分别对这两部分记录继续进 ...
- POJ 2247
#include<iostream> #include<algorithm> #include<vector> #include<string> #in ...
- 剑指offer四十五之扑克牌顺子(序列是否连续)
一.题目 LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决 ...
- 第6章—渲染web视图—SpringMVC+Thymeleaf 处理表单提交
SpringMVC+Thymeleaf 处理表单提交 thymleaf处理表单提交的方式和jsp有些类似,也有点不同之处,这里操作一个小Demo,并说明: 1.demo的结构图如下所示: pom.xm ...
- 安卓的SlidingMenu配置
最近用到了界面的优化,使用SlidingMenu开源库比较方便,为了方便学习,我整理了一下配置过程. 1.准备资料. 首先下载这两个ActionBarSherlock和SlidingMenu,如图:
- 图解-安卓中调用OpenGL
游戏开发中经常使用到OpenGL,当然很多人都喜欢直接用现有的游戏引擎,但相信了解的更多对你没有坏处 安卓开发中,采用的OpenGL ex2的规范,前几天看了下这个规范,整体上难度比1.0规范难度加大 ...