bzoj 4712: 洪水
[权限题][https://www.lydsy.com/JudgeOnline/status.php?problem_id=4712&jresult=4]
这道动态\(dp\)终于不是独立集/覆盖集了
我们来看看暴力转移
设\(dp_x\)表示把\(x\)子树内部全部切断的最小花费
显然有
\]
于是我们可以考虑把所有轻儿子的\(dp_v\)存下来
之后就能搞了
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define LL long long
#define re register
#define maxn 200005
#define inf 99999999999999
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n,m,num,__;
struct E{int v,nxt;}e[maxn<<1];
struct mat{LL a[2][2];}d[maxn<<2];
int l[maxn<<2],r[maxn<<2];
int deep[maxn],fa[maxn],pos[maxn],sum[maxn],son[maxn];LL dp[maxn];
int id[maxn],dfn[maxn],top[maxn],bot[maxn],head[maxn],a[maxn];
inline void C(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
void dfs1(int x) {
sum[x]=1;int maxx=-1;
for(re int i=head[x];i;i=e[i].nxt) {
if(deep[e[i].v]) continue;
deep[e[i].v]=deep[x]+1;fa[e[i].v]=x;
dfs1(e[i].v);sum[x]+=sum[e[i].v];
if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[x]=e[i].v;
}
}
int dfs2(int x,int topf) {
top[x]=topf;dfn[x]=++__,id[__]=x;
if(!son[x]) return bot[x]=x;
bot[x]=dfs2(son[x],topf);
for(re int i=head[x];i;i=e[i].nxt) {
if(top[e[i].v]) continue;
dfs2(e[i].v,e[i].v);
}
return bot[x];
}
inline mat operator*(mat a,mat b) {
mat c;
c.a[0][0]=min(a.a[0][0]+b.a[0][0],a.a[0][1]+b.a[1][0]);
c.a[0][1]=min(a.a[0][1]+b.a[1][1],a.a[0][0]+b.a[0][1]);
c.a[1][0]=min(a.a[1][0]+b.a[0][0],a.a[1][1]+b.a[1][0]);
c.a[1][1]=min(a.a[1][1]+b.a[1][1],a.a[1][0]+b.a[0][1]);
return c;
}
inline void pushup(int i) {d[i]=d[i<<1]*d[i<<1|1];}
inline void change(int i,int val) {d[i].a[0][1]=val;while(i) {i>>=1;pushup(i);}}
inline void push(int i,mat val) {d[i]=val;while(i) {i>>=1;pushup(i);}}
void build(int x,int y,int i) {
l[i]=x,r[i]=y;
if(x==y) {
int now=id[x];
for(re int j=head[now];j;j=e[j].nxt) {
if(deep[e[j].v]<deep[now]||son[now]==e[j].v) continue;
dp[now]+=dp[e[j].v];
}
if(son[now]) d[i].a[0][0]=dp[now];else d[i].a[0][0]=inf;
d[i].a[0][1]=a[now];
d[i].a[1][0]=inf,d[i].a[1][1]=0;
if(son[now]) dp[now]+=dp[son[now]];
if(!dp[now]||dp[now]>a[now]) dp[now]=a[now];pos[now]=i;
return;
}
int mid=x+y>>1;
build(mid+1,y,i<<1|1),build(x,mid,i<<1);
pushup(i);
}
mat query(int x,int y,int i) {
if(x<=l[i]&&y>=r[i]) return d[i];
int mid=l[i]+r[i]>>1;
if(y<=mid) return query(x,y,i<<1);
if(x>mid) return query(x,y,i<<1|1);
return query(x,y,i<<1)*query(x,y,i<<1|1);
}
int main() {
n=read();
for(re int i=1;i<=n;i++) a[i]=read();
for(re int x,y,i=1;i<n;i++) x=read(),y=read(),C(x,y),C(y,x);
deep[1]=1,dfs1(1),dfs2(1,1),build(1,n,1);
m=read();int x,y;char opt[2];
while(m--) {
scanf("%s",opt);x=read();
if(opt[0]=='Q') {
mat now=query(dfn[x],dfn[bot[x]],1);
printf("%lld\n",min(now.a[0][0],now.a[0][1]));
}
if(opt[0]=='C') {
y=read();a[x]+=y;
mat pre=query(dfn[top[x]],dfn[bot[x]],1);
change(pos[x],a[x]);
while(1) {
if(top[x]==1) break;
mat now=query(dfn[top[x]],dfn[bot[x]],1);
mat t=d[pos[fa[top[x]]]];
t.a[0][0]-=min(pre.a[0][0],pre.a[0][1]);
t.a[0][0]+=min(now.a[0][0],now.a[0][1]);
x=fa[top[x]];
pre=query(dfn[top[x]],dfn[bot[x]],1);push(pos[x],t);
}
}
}
return 0;
}
bzoj 4712: 洪水的更多相关文章
- 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: 洪水 挖坑待补
Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) # ...
- BZOJ 4712 洪水 (线段树+树剖动态维护DP)
题目大意:略 题目传送门 数据结构好题,但据说直接上动态DP会容易处理不少,然而蒟蒻不会.一氧化碳大爷说还有一个$log$的做法,然而我只会$log^{2}$的.. 考虑静态时如何处理,设$f[x]$ ...
- BZOJ 4712 洪水 动态dp(LCT+矩阵乘法)
把之前写的版本改了一下,这个版本的更好理解一些. 特地在一个链的最底端特判了一下. code: #include <bits/stdc++.h> #define N 200005 #def ...
- 4712: 洪水 基于链分治的动态DP
国际惯例的题面:看起来很神的样子......如果我说这是动态DP的板子题你敢信?基于链分治的动态DP?说人话,就是树链剖分线段树维护DP.既然是DP,那就先得有转移方程.我们令f[i]表示让i子树中的 ...
- LG3781 [SDOI2017]切树游戏
题意 题目描述 小Q是一个热爱学习的人,他经常去维基百科学习计算机科学. 就在刚才,小Q认真地学习了一系列位运算符,其中按位异或的运算符\(\oplus\)对他影响很大.按位异或的运算符是双目运算符. ...
- 并查集 - BZOJ 1104 [POI2007]洪水
BZOJ 1104 [POI2007]洪水 描述 AKD 市处在一个四面环山的谷地里.最近一场大暴雨引发了洪水,AKD 市全被水淹没了.Blue Mary,AKD 市的市长,召集了他的所有顾问(包括你 ...
- 【BZOJ】1104: [POI2007]洪水pow
题意 给一个\(n * m(1 \le n, m \le 1000)\)的矩阵,如果\(a_{i, j}\)为正表示城市.\(|a_{i, j}|(|a_{i, j}| \le 1000)\)是格子\ ...
随机推荐
- C#三大特性之 封装、继承、多态
一.封装: 封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类).被封装的对象通常被称为抽象数据类型. 封装的意义: 封装的意义在于保护或者防止代码(数据) ...
- nodejs简易代理服务器
直接代码: var http = require('http') var proxy = http.createServer(function (request, response) { var op ...
- Grpc helloworld demo的经验
GreeterGrpc.java这个文件是插件protoc-gen-grpc-java生成的 刚开始直接用类似如下的指令无法生成GreeterGrpc.java文件 protoc --java_ou ...
- Java设计模式—桥梁模式
终于又碰到了一个简单点的模式了. 桥梁模式也叫做桥接模式,定义如下: 将抽象和实现解耦,使得两者可以独立地变化. 这句话也太难理解了,桥梁模式是为了解决类继承的缺点而设计 ...
- mysql存储过程模板
CREATE DEFINER=`root`@`localhost` PROCEDURE `SP_test`(IN `nodeCode` varchar(100),IN `id` varchar(36) ...
- 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用)
问题描述: 有时候使用 apt-get 终端提示这样的错误信息: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用) E: 无法锁定管理目录(/var/lib/ ...
- EventTarge Node Docuement Element HTMLElement 关系
综述: 可以将其看做是依次继承的关系: Node Node A Node is an interface from which a number of DOM types inherit, and a ...
- Hbase集群部署
1.安装Hadoop集群 这个之前已经写过 2.安装Zookeeper 这个之前也已经写过 3.下载hbase,放到master机器,解压 4.修改hbase-env.sh,添加Java地址 expo ...
- 个人总结4-dbutils总结
昨天学习了dbutils的使用方法,简化了使用的步骤,可以使用三四步就可以写出来,queryRunner的使用方法有了简单的了解,目前可以使用dbutils实现最简单的增删改查. 今天准备学习准备写登 ...
- vs2015生成的mvc模板结构说明