bzoj 4712 洪水——动态DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4712
因为作为动态DP练习而找到,所以就用动态DP做了,也没管那种二分的方法。
感觉理解似乎加深了。
果然初始权值也都是非负的。
所以 dp[cr] 表示当前子树与自己的叶子都断开了的最小代价,则 dp[cr]=min{ sigma dp[v] , w[cr] }(v是cr的直接孩子)。
但这样的话,修改的时候需要把自己到根的路径都走一遍。不过查询是O(1)的,所以考虑分配一下。
走到根的过程如果是 log 的话就好了。那么不是倍增就是树剖。
考虑用树剖,s[cr] 表示 sigma dp[v] ( v是cr的轻儿子)。这样修改的话只要每次遇到别的重链就改一下它的 s 就行了。
考虑查询,可以从矩阵的角度看:
状态矩阵是2行1列,放 dp[cr] 和 0 ;转移矩阵是2行2列,[0][0]=s[cr],[0][1]=w[cr],[1][0]=0,[1][1]=0。转移的时候是[ i ][ j ]=min( [ i ][ j ] , [ i ][ k ]+[ k ][ j ] )。
于是树剖的线段树维护的就是转移矩阵的乘积,查询一个点到其所在重链底端的一段乘积即可。原本要乘一个状态,但那个是 [0][0]=0,[0][1]=0,所以把2行2列的 [0][0] 和 [0][1] 取个min作为dp[ ]。
然后就能以很慢的速度A了。
或者像这个人这样,好像能快个2504ms。https://www.cnblogs.com/GXZlegend/p/8710445.html
自己生硬地弄2×2矩阵果然不够好吗……这也启示我们,只要是线段树能维护的东西就行,不一定非是矩阵。关键是把轻儿子的信息带在身上,现求重儿子的信息。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
const int N=2e5+,INF=1e9+;
int n,m,hd[N],xnt,to[N<<],nxt[N<<],w[N];
int tot,dfn[N],rnk[N],top[N],son[N],siz[N],fa[N],bj[N],Ls[N<<],Rs[N<<];
ll dp[N];
ll Mn(ll a,ll b){return a<b?a:b;}
struct Matrix{
ll a[][];
Matrix(){a[][]=a[][]=a[][]=a[][]=INF;}
Matrix operator+ (const Matrix &b)const
{
Matrix c;
for(int i=;i<=;i++)
for(int k=;k<=;k++)
for(int j=;j<=;j++)
c.a[i][j]=Mn(c.a[i][j],a[i][k]+b.a[k][j]);
return c;
}
}g[N],t[N<<];
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='') ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return fx?ret:-ret;
}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void dfs(int cr)
{
siz[cr]=;
for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=fa[cr])
{
fa[v]=cr; dfs(v); siz[cr]+=siz[v];
siz[v]>siz[son[cr]]?son[cr]=v:;
}
}
void dfsx(int cr)
{
dfn[cr]=++tot; rnk[tot]=cr;
dp[cr]=w[cr]; ll tmp=;
if(son[cr])top[son[cr]]=top[cr],dfsx(son[cr]);
g[cr].a[][]=INF; g[cr].a[][]=w[cr];
g[cr].a[][]=g[cr].a[][]=;
if(!son[cr]){bj[top[cr]]=dfn[cr];return;} for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=fa[cr]&&v!=son[cr])
{
top[v]=v;dfsx(v);
tmp+=dp[v];
}
g[cr].a[][]=tmp; dp[cr]=Mn(w[cr],tmp+dp[son[cr]]);
}
void build(int l,int r,int cr)
{
if(l==r){t[cr]=g[rnk[l]];return;}
int mid=l+r>>;
ls=++tot; build(l,mid,ls);
rs=++tot; build(mid+,r,rs);
t[cr]=t[ls]+t[rs];
}
void updt(int l,int r,int cr,int p)
{
if(l==r){t[cr]=g[rnk[l]];return;}
int mid=l+r>>;
if(p<=mid)updt(l,mid,ls,p);
else updt(mid+,r,rs,p);
t[cr]=t[ls]+t[rs];
}
Matrix query(int l,int r,int cr,int L,int R)
{
if(l>=L&&r<=R)return t[cr];
int mid=l+r>>;
if(R<=mid)return query(l,mid,ls,L,R);
if(mid<L)return query(mid+,r,rs,L,R);
return query(l,mid,ls,L,R)+query(mid+,r,rs,L,R);
}
Matrix calc(int cr){ return query(,n,,dfn[cr],bj[cr]);}
void cz(int x,int y)
{
g[x].a[][]+=y;
Matrix k1=calc(top[x]); updt(,n,,dfn[x]); Matrix k2=calc(top[x]);
while(fa[top[x]])
{
g[fa[top[x]]].a[][]+=Mn(k2.a[][],k2.a[][])-Mn(k1.a[][],k1.a[][]);
x=fa[top[x]];
k1=calc(top[x]); updt(,n,,dfn[x]); k2=calc(top[x]);
}
}
int main()
{
n=rdn();for(int i=;i<=n;i++)w[i]=rdn();
for(int i=,u,v;i<n;i++)
{
u=rdn(); v=rdn(); add(u,v); add(v,u);
}
dfs(); top[]=; dfsx(); tot=; build(,n,);
m=rdn(); char ch[];
for(int i=,x,y;i<=m;i++)
{
scanf("%s",ch);
if(ch[]=='C')
{
x=rdn(); y=rdn(); cz(x,y);
}
else
{
x=rdn(); Matrix d=query(,n,,dfn[x],bj[top[x]]);
printf("%lld\n",Mn(d.a[][],d.a[][]));
}
}
return ;
}
bzoj 4712 洪水——动态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 ...
- BZOJ 4712 洪水 (线段树+树剖动态维护DP)
题目大意:略 题目传送门 数据结构好题,但据说直接上动态DP会容易处理不少,然而蒟蒻不会.一氧化碳大爷说还有一个$log$的做法,然而我只会$log^{2}$的.. 考虑静态时如何处理,设$f[x]$ ...
- bzoj 4712: 洪水
[权限题][https://www.lydsy.com/JudgeOnline/status.php?problem_id=4712&jresult=4] 这道动态\(dp\)终于不是独立集/ ...
- 【bzoj4712】洪水 动态dp
不难发现此题是一道动态$dp$题 考虑此题没有修改怎么做,令$f[i]$表示让以$i$为根的子树被覆盖的最小花费,不难推出$f[i]=min(\sum_{j∈son[i]} f[j],val[i])$ ...
- BZOJ4712洪水——动态DP+树链剖分+线段树
题目描述 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到 山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地爬山堵水.那么 ...
- BZOJ 4712: 洪水 挖坑待补
Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) # ...
- 4712: 洪水 基于链分治的动态DP
国际惯例的题面:看起来很神的样子......如果我说这是动态DP的板子题你敢信?基于链分治的动态DP?说人话,就是树链剖分线段树维护DP.既然是DP,那就先得有转移方程.我们令f[i]表示让i子树中的 ...
- 【BZOJ4712】洪水(动态dp)
[BZOJ4712]洪水(动态dp) 题面 BZOJ 然而是权限题QwQ,所以粘过来算了. Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开 ...
随机推荐
- Linux基本命令 帮助命令
命令名称:man 英文原意:manual 命令所在路径:/usr/bin/man 执行权限:所有用户 语法:man [命令或者配置文件] 功能描述:获取帮助信息 例如:man ls 查看ls命令的帮助 ...
- php多个数组同键名键值相加合并
//任意多个相同键值的数组合并相加 //预先将所要合并的数组组装成一个新的数组 // $arr = array( // array( // 'user_id' => 100, // 'goods ...
- readonly与disabled
readonly与disabled都能将元素设为不可编辑状态,但他们有许多区别: 1.样式 readonly与一般样式一样,disabled会将元素背景设为灰色 2.应用范围 readonly只对in ...
- ibecon后台运行
程序被硬关闭后,只能执行这三个回调,而且必须写在appdelegate中,退出ibeacons信息区域时会有延时10秒左右,进入时无延时 - (void)locationManager:(CLLoca ...
- Asp.net 5 (MVC6) Areas 分区
1. Startup.cs 类的 Configure方法中, 加入Area路由设置代码: //app.UseMvcWithDefaultRoute(); app.UseMvc(routes=> ...
- StringTemplateLoader的用法
作为一个模板框架,freemarker的功能还是很强大的.在模板处理方面,freemarker有多种形式,最常见的方式是将模板文件放在一个统一的文件夹下面,如下形式:Configuration cfg ...
- 织梦dedecms 自带采集的缩略图地址后面有“/”斜杠的解决方法
本来想偷懒在网上找一些文档去解决织梦采集缩略图地址带“/”的问题的,可是找了找发现没有人写出解决方法,只好自己动手了. 过程很复杂,找了问题的原因也是找了半天,自己一点一点的测试.最后找到了问题所在. ...
- b树的实现(c++)
转自:http://blog.chinaunix.net/uid-20196318-id-3030529.html B树的定义 假设B树的度为t(t>=2),则B树满足如下要求:(参考算法导论) ...
- hibernate学习(3)
0 列表功能实现 1 表与表之间关系回顾 (1)一对多(客户和联系人) (2)多对多(用户和角色) 2 hibernate 一对多操作 (1)一对多映射配置 (2)一对多级联保存 (3)一对多级联删除 ...
- decimal与 float的区别
decimal 数据类型最多可存储 38 个数字,所有数字都能够放到小数点的右边.decimal 数据类型存储了一个准确(精确)的数字表达法:不存储值的近似值. 定义 decimal 的列.变量和 ...