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)\)是格子\ ...
随机推荐
- 信号量 P V测试详解
信号量 当我们编写的程序使用了线程时,不管它是运行在多用户系统上,多进程系统上,还是运行在多用户多进程系统上,我们通常会发现,程序中存在着一部分临界代码,我们需要确保只有一个进程可以进入这个临界代码并 ...
- ASP.NET 使用ajaxfileupload.js插件出现上传较大文件失败的解决方法(ajaxfileupload.js第一弹)
在写这篇的时候本来想把标题直接写成报错的提示,如下: “SecurityError:Blocked a frame with origin "http://localhost:55080&q ...
- 一键安装lamp环境出现的问题
前言:之前安装lamp是独立安装的,安装扩展很方便,现在用这个一键安装包,不知道怎么样,尝试一把. Part1:安装过程中出现的问题 error: utf8_mime2text() has new s ...
- ArrayList封装
package com.cn.test.jihe; import java.util.Arrays; /** * * insert * delete * update * get * */ publi ...
- HDU 1757 矩阵求第n的递推式
A Simple Math Problem Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
- Jquery中动态生成的元素没有点击事件或者只有一次点击事件
今天用jq做动态生成的元素的click事件时,click只执行了一次,当然有些朋友可能根本没执行, 执行了一次的原因是因为可能有函数加载了一遍,一次都没执行的可能是没绑定对象或者jq版本问题, 动态生 ...
- BZOJ4659:lcm
传送门 题目所给的不合法的条件可以转化为 \[\exists p,p^2|gcd(a,b) \Leftrightarrow \mu(gcd(a,b))\ne 0\] 那么 \[ans=\sum_{a= ...
- 【问题:发现与解决】angularJs指令在dijit控件中的使用
由于公司主要用的JS框架是DOJO,最近又运用了angularJs.因此,不可能避免的遇到dojo控件和angular指令(directive)共用时遇到的一些问题,问题如下: <input ...
- Android 二次打包(封装)AAR实用指南
前言 上次文章Android SDK开发与使用的那些事儿说到如何在aar里集成导入的aar,也就是二次封装aar的问题,一带而过,难免不过瘾.在封装这条路上也遇到了不少坑,现在将此方法详细记录下来. ...
- Java面试通关要点【问题汇总篇】
基础篇 基本功: 面向对象的特征 final, finally, finalize 的区别 int 和 Integer 有什么区别 重载和重写的区别 抽象类和接口有什么区别 说说反射的用途及实现 说说 ...