题目: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的更多相关文章

  1. bzoj 4712 洪水 —— 动态DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4712 设 f[x] = min(∑f[u] , a[x]),ls = ∑f[lson] 矩阵 ...

  2. BZOJ 4712 洪水 动态dp(LCT+矩阵乘法)

    把之前写的版本改了一下,这个版本的更好理解一些. 特地在一个链的最底端特判了一下. code: #include <bits/stdc++.h> #define N 200005 #def ...

  3. BZOJ 4712 洪水 (线段树+树剖动态维护DP)

    题目大意:略 题目传送门 数据结构好题,但据说直接上动态DP会容易处理不少,然而蒟蒻不会.一氧化碳大爷说还有一个$log$的做法,然而我只会$log^{2}$的.. 考虑静态时如何处理,设$f[x]$ ...

  4. bzoj 4712: 洪水

    [权限题][https://www.lydsy.com/JudgeOnline/status.php?problem_id=4712&jresult=4] 这道动态\(dp\)终于不是独立集/ ...

  5. 【bzoj4712】洪水 动态dp

    不难发现此题是一道动态$dp$题 考虑此题没有修改怎么做,令$f[i]$表示让以$i$为根的子树被覆盖的最小花费,不难推出$f[i]=min(\sum_{j∈son[i]} f[j],val[i])$ ...

  6. BZOJ4712洪水——动态DP+树链剖分+线段树

    题目描述 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到 山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地爬山堵水.那么 ...

  7. BZOJ 4712: 洪水 挖坑待补

    Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) # ...

  8. 4712: 洪水 基于链分治的动态DP

    国际惯例的题面:看起来很神的样子......如果我说这是动态DP的板子题你敢信?基于链分治的动态DP?说人话,就是树链剖分线段树维护DP.既然是DP,那就先得有转移方程.我们令f[i]表示让i子树中的 ...

  9. 【BZOJ4712】洪水(动态dp)

    [BZOJ4712]洪水(动态dp) 题面 BZOJ 然而是权限题QwQ,所以粘过来算了. Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开 ...

随机推荐

  1. Go 外部排序-网络版

    目录结果 main.go package main import ( "NetworkSort/pipeline" "fmt" "os" & ...

  2. 服务器windows 2003 安装SQL 2000+SP4

    (在windows 2003安装SQL 2000,对于03系统是没有32位和64位之分的) (32位系统需要重启机器,64不需要) 在站点下载数据库 解压后有两个文件夹 首先安装SQL2000 第1步 ...

  3. springmvc返回视图(解析)

    1.什么是视图? 视图就是展示给用户看的结果.可以是很多形式,例如:html.JSP.excel表单.Word文档.PDF文档.JSON数据.freemarker模板视图等等. 2.传统JSP和JST ...

  4. HMM代码实现

    按照网上的代码,自己敲了一下,改了一点点,理解加深了一下. 还有训练HMM的EM算法没看懂,下次接着看: 参考连接:http://www.cnblogs.com/hanahimi/p/4011765. ...

  5. Spring之rmi实例演示

    环境介绍:本文中服务端客户端使用的都是ssm框架,配置文件分为spring_servlet.xml,spring_service.xml,mybatis.xml 在spring里面使用rmi完成远程调 ...

  6. awk实现替换字符串中指定位置之间的内容

    # 显示第xx行的第yy列的一个字符sed -n 'xx,xxp' file | awk '{print substr($0,yy,1);}' # 修改第xx行的第yy列的一个字符Chr,并保存为新文 ...

  7. 【2039】checker(Dp)

    我今天脑子貌似又好使了一点,可以做一做DP中的水题了. 这个题难度蓝色,纯属是做的人太少了虚高. 这个题很显然的是可以用一个顺序一个逆序这两个大水转移方程轻松转移出到达这个地方最少需要的棋子数量,然后 ...

  8. DanceLink

    DanceLink是一个可以解决精确覆盖和重复覆盖的搜索算法 重复覆盖就是在精确覆盖的remove等处做改变 都是十字循环链表 精确覆盖 给出一个01矩阵 要求选择几行 使每一列都有且仅有一个1 在求 ...

  9. setStyleSheet 一些QSS设置的集合

    setStyleSheet 设置的一些集合,一部分源码和截图来自 http://blog.sina.com.cn/s/articlelist_2801495241_0_1.html 1. 设置QLab ...

  10. CentOS 6.6 中jdk1.6的安装和配置方法

    Linux中JDK1.6的安装和配置方法 一.安装 创建安装目录,在/usr/java下建立安装路径,并将文件考到该路径下: # mkdir /usr/java 1.jdk-6u11-linux-i5 ...