bzoj4712 洪水(动态dp)
看起来很模板的一个题啊
qwq
但是我还是wei
题目要求的是一个把根节点和所有叶子断开连接的最小花费。
还是想一个比较\(naive\)的做法
我们令\(dp1[i]\)表示,在\(i\)的子树内,把叶子全都隔断的最小代价,那么
\]
但是这样暴力并不能通过这个题。
考虑怎么来优化更新的过程呢。
由于是树上问题,根据套路,我们对原树进行树链剖分。
令\(dp[i]\)表示除去重儿子的所有\(dp1[p]\)的和。
那么我们重新定义矩阵乘法\(c[i][j]=max(c[i][j],a[i][k]+b[k][j])\)之后,就可以通过矩阵来完成转移了
我们令\(g\)表示包含重儿子的\(ans\),然后令\(f\)表示上述的\(dp[i]\)
令\(p\)表示重儿子。
那么不难发现
g[p] 0
g[p] 0
和
f[i] +inf
val[i] 0
做矩阵乘法之后,就能得到
g[i] 0
g[i] 0
那我们可以直接用线段树来维护矩阵乘法来进行快速修改和求值了。
但是有一个需要注意的地方就是,对于重链链尾的所有元素的对应转移矩阵要特殊处理,因为他们的\(g\)是等于\(f\)的。
那么修改的时候,先进行单点修改(要特判链尾)
然后依次修改每一条重链的\(fa\)的转移矩阵即可。
qwq一开始有很多地方都没有想明白,就很wei
细节就直接看代码吧
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 2e5+1e2;
const int maxm = 2*maxn;
const int inf = 1e18;
struct Ju{
int x,y;
int a[3][3];
Ju operator * (Ju b)
{
Ju ans;
ans.x=ans.y=2;
memset(ans.a,0x3f,sizeof(ans.a));
for (int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
for (int k=1;k<=y;k++)
{
ans.a[i][j]=min(ans.a[i][j],a[i][k]+b.a[k][j]);
}
return ans;
}
};
int point[maxn],nxt[maxm],to[maxm],val[maxn];
int cnt,n,m;
Ju pre[maxn];
Ju f[4*maxn];
int top[maxn],newnum[maxn],tail[maxn];
int fa[maxn],son[maxn],size[maxn];
int q;
int back[maxn];
int dp1[maxn],dp[maxn];
int sum[maxn];
//dp[x] doesn't include son[x]
//这个dp数组实质上就是一个sum的形式。
void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
}
void up(int root)
{
f[root]=f[2*root+1]*f[2*root];
}
void build(int root,int l,int r)
{
if (l==r)
{
int ymh = back[l];
f[root].x=f[root].y=2;
if (tail[top[ymh]]==ymh)
{
f[root].a[1][1]=f[root].a[2][1]=dp1[ymh];
}
else
{
f[root].a[1][1]=dp[ymh];
f[root].a[1][2]=inf;
f[root].a[2][1]=val[ymh];
}
return;
}
int mid = l+r >> 1;
build(2*root,l,mid);
build(2*root+1,mid+1,r);
up(root);
}
void update(int root,int l,int r,int x,Ju p)
{
if(l==r)
{
f[root]=p;
return;
}
int mid = l+r >> 1;
if (x<=mid) update(2*root,l,mid,x,p);
else update(2*root+1,mid+1,r,x,p);
up(root);
}
Ju query(int root,int l,int r,int x,int y)
{
if (x<=l && r<=y)
{
return f[root];
}
int mid = l+r >> 1;
if (x>mid) return query(2*root+1,mid+1,r,x,y);
if (y<=mid) return query(2*root,l,mid,x,y);
return query(2*root+1,mid+1,r,x,y)*query(2*root,l,mid,x,y);
}
void dfs1(int x,int faa)
{
size[x]=1;
int maxson=-1;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (p==faa) continue;
fa[p]=x;
dfs1(p,x);
size[x]+=size[p];
if (size[p]>maxson)
{
maxson=size[p];
son[x]=p;
}
}
}
int tot;
void dfs2(int x,int chain)
{
top[x]=chain;
tail[chain]=x;
newnum[x]=++tot;
back[tot]=x;
if (!son[x]) return;
dfs2(son[x],chain);
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (!newnum[p]) dfs2(p,p);
}
}
void solve(int x,int fa)
{
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (p==fa) continue;
solve(p,x);
sum[x]+=dp1[p];
}
if (!son[x]) dp1[x]=val[x];
else dp1[x]=min(sum[x],val[x]);
dp[x]=sum[x]-dp1[son[x]];
}
void modify(int x,int y)
{
Ju tmp = query(1,1,n,newnum[x],newnum[x]);
tmp.a[2][1]+=y;
val[x]+=y;
if (tail[top[x]]==x) tmp.a[1][1]+=y;
update(1,1,n,newnum[x],tmp);
for (int now = top[x];now!=1;now=top[now])
{
int faa = fa[now];
Ju ymh = query(1,1,n,newnum[faa],newnum[faa]);
Ju lyf = query(1,1,n,newnum[now],newnum[tail[top[now]]]);
ymh.a[1][1]+=(lyf.a[1][1]-pre[now].a[1][1]);
update(1,1,n,newnum[faa],ymh);
pre[now]=lyf;
now = fa[now];
}
}
signed main()
{
n=read();
for (int i=1;i<=n;i++) val[i]=read();
for (int i=1;i<n;i++)
{
int x=read(),y=read();
addedge(x,y);
addedge(y,x);
}
dfs1(1,0);
dfs2(1,1);
solve(1,0);
build(1,1,n);
for (int i=1;i<=n;i++)
{
pre[i]=query(1,1,n,newnum[i],newnum[tail[top[i]]]);
}
q=read();
for (int i=1;i<=q;i++)
{
char s[10];
scanf("%s",s+1);
if (s[1]=='Q')
{
int x=read();
Ju now = query(1,1,n,newnum[x],newnum[tail[top[x]]]);
cout<<now.a[1][1]<<"\n";
}
else
{
int x=read(),y=read();
modify(x,y);
}
}
return 0;
}
bzoj4712 洪水(动态dp)的更多相关文章
- BZOJ4712洪水——动态DP+树链剖分+线段树
题目描述 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到 山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地爬山堵水.那么 ...
- 【bzoj4712】洪水 动态dp
不难发现此题是一道动态$dp$题 考虑此题没有修改怎么做,令$f[i]$表示让以$i$为根的子树被覆盖的最小花费,不难推出$f[i]=min(\sum_{j∈son[i]} f[j],val[i])$ ...
- bzoj 4712 洪水——动态DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4712 因为作为动态DP练习而找到,所以就用动态DP做了,也没管那种二分的方法. 感觉理解似乎 ...
- bzoj 4712 洪水 —— 动态DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4712 设 f[x] = min(∑f[u] , a[x]),ls = ∑f[lson] 矩阵 ...
- BZOJ 4712 洪水 动态dp(LCT+矩阵乘法)
把之前写的版本改了一下,这个版本的更好理解一些. 特地在一个链的最底端特判了一下. code: #include <bits/stdc++.h> #define N 200005 #def ...
- 【BZOJ4712】洪水(动态dp)
[BZOJ4712]洪水(动态dp) 题面 BZOJ 然而是权限题QwQ,所以粘过来算了. Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开 ...
- [bzoj4712]洪水_动态dp
洪水 bzoj-4712 题目大意:给定一棵$n$个节点的有根树.每次询问以一棵节点为根的子树内,选取一些节点使得这个被询问的节点包含的叶子节点都有一个父亲被选中,求最小权值.支持单点修改. 注释:$ ...
- 【bzoj4712】洪水 树链剖分+线段树维护树形动态dp
题目描述 给出一棵树,点有点权.多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值. 输入 输入文件第一行包含 ...
- 4712: 洪水 基于链分治的动态DP
国际惯例的题面:看起来很神的样子......如果我说这是动态DP的板子题你敢信?基于链分治的动态DP?说人话,就是树链剖分线段树维护DP.既然是DP,那就先得有转移方程.我们令f[i]表示让i子树中的 ...
- 动态 DP 学习笔记
不得不承认,去年提高组 D2T3 对动态 DP 起到了良好的普及效果. 动态 DP 主要用于解决一类问题.这类问题一般原本都是较为简单的树上 DP 问题,但是被套上了丧心病狂的修改点权的操作.举个例子 ...
随机推荐
- go进阶--测试
目录 1.单元测试 1.1项目结构 1.2 源代码文件 1.3 单元测试 1.4 执行测试 1.5 单元测试总结 2.性能测试 2.1 项目结构 2.2 源码文件 2.3 测试文件 2.4 执行测试 ...
- QT学习日记篇-02-QT信号和槽
课程大纲: <1>给控件改名字 随着UI界面的控件变多,如果使用系统自带的名称,后期会让人不明觉厉,说白了,就是掌握C++的命名规则:易懂,条例清晰,人性化 方法:直接点击控件,进入右侧对 ...
- vue 引用高德地图
vue 引用地图之傻瓜式教程(复制粘贴即可用) npm 下载 npm install vue-amap --save main.js 代码 import AMap from 'vue-amap'; V ...
- zabbix 历史数据处理
问题描述 zabbix server 平稳运行有一段时间了,但是最近问题却来了,今天早上收到zabbixserver磁盘空间不足的告警.通过查看之后发现是大部分数据是zabbix 库的的数据 在进一步 ...
- shell运算方式
1.(())--整数运算 [root@m01 /server/scripts]# a=1 [root@m01 /server/scripts]# b=2 [root@m01 /server/scrip ...
- 【Azure 应用服务】Python flask 应用部署在Aure App Service中作为一个子项目时,解决遇见的404 Not Found问题
问题描述 在成功的部署Python flask应用到App Service (Windows)后,如果需要把当前项目(如:hiflask)作为一个子项目(子站点),把web.config文件从wwwr ...
- noip模拟测试50
考试过程:开题顺序1,2,3,做T1的时候我想到了要求的东西,就是分成尽量少的段使得每段之和>=k,但是我不会求,就打了个暴力走了,然后看T2,这题我觉得和之前做过的一道题比较像,因为我觉得\( ...
- Appium问题解决方案(6)- Java堆栈错误:java.lag.ClassNotFoundException:org.eclipse.swt.widets.Control
背景 运行脚本出现 SWT folder '..\lib\location of your Java installation.' does not exist. Please set ANDROID ...
- docker-compose up -d nginx 报错
在阿里云ECS上创建nginx容器时,报错如上图. The solution: In your Dockerfile, before running any apt commands, add the ...
- clickonce的密钥到期问题处理
最近clickonce的密钥到期了,在网上找了些文章用来修改密钥的到期时间,已成功生成新密钥,好不好使暂时未测. 在此小结一下,以备参考: 1.在原密钥所属电脑上cmd执行如下命令 renewcert ...