『NOIP 2019Day2 T3』 保卫王国(defense)
重温NOIP2018的试题,发现只要好好想想还是能想出一些东西的。
比如说本题是一个DDP的模板题,硬是做成了倍增优化DP的题目。
对于给出的$n$个节点的树,每个点都有点权$v_i$,共$Q$次询问。
每次询问指定两个点的状态取或者不取,询问树中最小权覆盖集。
如果最小权覆盖集不存在,输出$-1$
对于$100\%$保证$1 \leq n,m \leq 10^5 , 1 \leq v_i \leq 10^9$
Solution :
我们设$g[u][0/1]$表示节点$u$是否选择,$u$的子树最小权覆盖集。
一个显然的转移是$g[u][0] = \sum\limits_{v \in u_{son}} g[v][1] , g[u][1] = val[u] + \sum\limits_{v \in u_{son}} min(g[v][0],g[v][1])$
为了解决$Q$个询问,我们需要设倍增数组来优化上述转移。
设$其中f[u][i][p][q] ( 其中p,q =0,1)$表示从$father(u)$到$u$向上跳$2^i$步的节点,其中$u$状态是$p $,$u$向上跳$2^i$得到的节点状态是$q$这段贡献最小值。
我们显然可以通过一次$dfs$,计算出$f[u][0][0/1][0/1] , g[u][0/1]$的值
- $f[u][0][0][0] = inf$
- $f[u][0][0][1] = val[father(u)] + \sum\limits_{v \in father(u)_{son} v \neq u}min\{g[v][0],g[v][1]\}$
- $f[u][0][1][0] =\sum\limits_{v \in father(u)_{son}} g[v][1]$
- $f[u][0][1][1]= val[father(u)] + \sum\limits_{v \in father(u)_{son} v \neq u}min\{g[v][0],g[v][1]\}$
然后我们也能通过$O(n \ log_2 \ n)$的复杂度预处理上述的倍增的数组,和$lca$的数组
处理每个询问的时候,把$u,v$在同一条链上的情况和$u,v$不在一条链上的情况进行讨论
(主要是向上跳的位置及贡献计算不同)
在向上跳的时候记录两个变量$ret0,ret1$表示当前节点取或不取当前的子树最小权覆盖集。
由于向上跳的步数倍增预处理完毕,一次询问最多只会向上跳$log_2n$步,
所以本题的时间复杂度就是$O((n+m) log_2 n )$
# include <bits/stdc++.h>
# define int long long
# define inf (1e12)
using namespace std;
const int N=5e5+;
struct rec{ int pre,to;}a[N<<];
int n,m,tot; char type[];
int f[N][][][],g[N][],d[N][],dep[N];
int sum1[N],sum2[N],head[N],val[N];
inline int read()
{
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
void write(int x) {
if (x<) putchar('-'),x=-x;
if (x>) write(x/);
putchar(''+x%);
}
void adde(int u,int v) {
a[++tot].pre=head[u];
a[tot].to=v;
head[u]=tot;
}
void dfs1(int u,int fa) {
dep[u]=dep[fa]+;
g[u][]=; g[u][]=val[u]; d[u][]=fa;
sum1[u]=; sum2[u]=;
for (int i=head[u];i;i=a[i].pre) {
int v=a[i].to; if (v==fa) continue;
dfs1(v,u);
g[u][]+=g[v][];
g[u][]+=min(g[v][],g[v][]);
sum1[u]+=g[v][];
sum2[u]+=min(g[v][],g[v][]);
}
}
void dfs2(int u,int fa) {
for (int i=head[u];i;i=a[i].pre) {
int v=a[i].to; if (v==fa) continue;
dfs2(v,u);
}
if (u != ) {
f[u][][][] = inf;
f[u][][][] = val[fa] + sum2[fa] - min(g[u][],g[u][]);
f[u][][][] = sum1[fa] - g[u][];
f[u][][][] = val[fa] + sum2[fa] - min(g[u][],g[u][]);
}
}
int lca(int u,int v) {
if (dep[u]<dep[v]) swap(u,v);
for (int i=;i>=;i--)
if (dep[d[u][i]]>=dep[v]) u=d[u][i];
if (u==v) return u;
for (int i=;i>=;i--)
if (d[u][i]!=d[v][i]) u=d[u][i],v=d[v][i];
return d[u][];
}
int work2(int u,int op1,int v,int op2) {
int ret0=g[u][],ret1=g[u][];
if (op1 == ) ret0=inf; else ret1=inf;
bool flag = true;
int tmp0,tmp1;
for (int i=;i>=;i--) {
if (dep[d[u][i]]<=dep[v]) continue;
tmp0=ret0,tmp1=ret1;
ret0 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
ret1 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
u = d[u][i];
} tmp0=ret0,tmp1=ret1;
ret0 = tmp1 + sum1[v] - g[u][];
ret1 = min(tmp1,tmp0) + sum2[v] - min(g[u][],g[u][]) + val[v];
if (op2 == ) ret1=inf; else ret0=inf;
u = v;
for (int i=;i>=;i--) {
if (dep[d[u][i]]<dep[]) continue;
tmp0=ret0,tmp1=ret1;
ret0 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
ret1 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
u=d[u][i];
}
int ans = min(ret0,ret1);
if (ans>=inf) return -; else return ans;
}
int work(int u,int op1,int v,int op2) {
if (dep[u]<dep[v]) swap(u,v),swap(op1,op2);
int l=lca(u,v);
if (l == v) return work2(u,op1,v,op2);
int ret0=g[u][],ret1=g[u][];
if (op1 == ) ret0=inf; else ret1=inf;
bool flag = true; int tmp0,tmp1;
for (int i=;i>=;i--) {
if (dep[d[u][i]]<=dep[l]) continue;
tmp0=ret0,tmp1=ret1;
ret0 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
ret1 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
u = d[u][i];
}
int val1[]; val1[] = ret0; val1[] = ret1;
ret0=g[v][],ret1=g[v][];
if (op2 == ) ret0=inf; else ret1=inf;
flag = true;
for (int i=;i>=;i--) {
if (dep[d[v][i]]<=dep[l]) continue;
tmp0=ret0,tmp1=ret1;
ret0 = min(tmp0+f[v][i][][],tmp1+f[v][i][][]);
ret1 = min(tmp0+f[v][i][][],tmp1+f[v][i][][]);
v = d[v][i];
}
int val2[]; val2[] = ret0; val2[] = ret1;
ret0 = val1[]+val2[]+sum1[l]-g[u][]-g[v][];
ret1 = val[l] + min(val1[],val1[]) + min(val2[],val2[]) + sum2[l] - min(g[u][],g[u][]) - min(g[v][],g[v][]);
u = l;
for (int i=;i>=;i--) {
if (dep[d[u][i]]<dep[]) continue;
tmp0=ret0,tmp1=ret1;
ret0 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
ret1 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
u=d[u][i];
} int ans = min(ret0,ret1);
if (ans>=inf) return -; else return ans;
}
signed main()
{
n=read();m=read(); scanf("%s",type);
for (int i=;i<=n;i++) val[i]=read();
for (int i=;i<=n;i++) {
int u=read(),v=read();
adde(u,v); adde(v,u);
}
dfs1(,); dfs2(,);
for (int i=;i<=;i++)
for (int j=;j<=n;j++)
d[j][i]=d[d[j][i-]][i-];
for (int i=;i<=;i++)
for (int u=;u<=n;u++) {
f[u][i][][]=f[u][i][][]=f[u][i][][]=f[u][i][][]=inf;
for (int p=;p<=;p++) {
f[u][i][][] = min(f[u][i][][],f[u][i-][][p] + f[d[u][i-]][i-][p][]);
f[u][i][][] = min(f[u][i][][],f[u][i-][][p] + f[d[u][i-]][i-][p][]);
f[u][i][][] = min(f[u][i][][],f[u][i-][][p] + f[d[u][i-]][i-][p][]);
f[u][i][][] = min(f[u][i][][],f[u][i-][][p] + f[d[u][i-]][i-][p][]);
}
}
while (m--) {
int u=read(),op1=read(),v=read(),op2=read();
int ans = work(u,op1,v,op2);
write(ans); putchar('\n');
}
return ;
}
defense
『NOIP 2019Day2 T3』 保卫王国(defense)的更多相关文章
- 『保卫王国 树上倍增dp』
保卫王国 Description Z 国有n座城市,n - 1条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻扎军队.驻扎军队需 ...
- 竞赛题解 - NOIP2018 保卫王国
\(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...
- js实现『加载更多』功能实例
DEMO : 滚动加载示例 关于如何实现『加载更多』功能,网上有插件可用,例如比较著名的使用iscroll.js实现的上拉加载更多.下拉刷新功能. 但实际用起来却是很麻烦.由于是第三方插件,要按照对方 ...
- 『Asp.Net 组件』Asp.Net 服务器组件 内嵌JS:让自己的控件动起来
代码: using System; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace ...
- 2018-2019-2 20165221『网络对抗技术』Exp4:恶意代码分析
2018-2019-2 20165221『网络对抗技术』Exp4:恶意代码分析 实验要求: 是监控你自己系统的运行状态,看有没有可疑的程序在运行. 是分析一个恶意软件,就分析Exp2或Exp3中生成后 ...
- 『Asp.Net 组件』Asp.Net 服务器组件 内嵌图片:自己的图片控件
代码: using System; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace ...
- 『Asp.Net 组件』第一个 Asp.Net 服务器组件:自己的文本框控件
代码: using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace DemoWebControl ...
- 『Asp.Net 组件』Asp.Net 服务器组件 的开发优势和劣势
在写<Asp.Net 服务器组件系列文档>之前,笔者不才,揣测微软战略用意: 微软利益诉求莫过于 微软产品和技术的市场份额: 因此,微软战略之一莫过于将 所有开发人员 团聚在 微软周围,以 ...
- 2017-2018-2 20155303『网络对抗技术』Exp6:信息收集与漏洞扫描
2017-2018-2 20155303『网络对抗技术』 Exp6:信息收集与漏洞扫描 --------CONTENTS-------- 一.原理与实践说明 1.实践内容 2.基础问题 二.实践过程记 ...
随机推荐
- 代理、反射、注解、hook
代理 通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,扩展目标对象的功能. 代理对象拦截真实对象的方法调用,在真实对象调用前/后实现自己的逻辑调用 这里使用到编程中的一个思想:不 ...
- ASP.NET_正则表达式_匹配HTML中的一行或多行
一.匹配数字串/flash/([0-9]+).htm 二.匹配不含双引号的字符串<p class=\"w490\">([^\"]+)</p> 三. ...
- C# 日期格式化以及日期常用方法
一.日期格式化 1.ToString() d 月中的某一天.一位数的日期没有前导零. dd 月中的某一天.一位数的日期有一个前导零. ddd 周中某天的缩写名称,在 AbbreviatedDayNam ...
- Visual Studio高分屏下Winform界面变形
现在高分屏的电脑越来越多,2K屏,4K屏层出不穷,对于.net开发人员来说,尤其是Winform开发者, 分辨率一直是个比较头疼的事情,屏幕分辨率高了,如果仍然设置显示100%,会导致字体非常小,影响 ...
- layer插件loading快速应用示例
1.页面引用<link rel="stylesheet" href="../Js/layer/skin/layer.css" /><scri ...
- 【weixin】微信支付---Native支付模式二(PC端支付大多采用此模式)
[模式二]:商户后台系统调用微信支付[统一下单API]生成预付交易,将接口返回的链接生成二维码,用户扫码后输入密码完成支付交易.注意:该模式的预付单有效期为2小时,过期后无法支付 模式二与模式一相比, ...
- C99 inline关键字
C99 inline 一直以来都用C++用得比较多,这个学期做操作系统的课设用回了C,结果一波內联函数居然链接不过去--查了查资料,C99引入的inline和C++的inline语义区别是很大的,我算 ...
- JS和JS是IE上JavaScript或JScript的缩写。
JS和JS是IE上JavaScript或JScript的缩写.javascript是所有浏览器的开放式标准脚本语言JScript是微软自己的开放式脚本语言标准,只有微软的IE浏览器遵循.JScript ...
- linux命令详解——top
简介 TOP是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系 ...
- casperjs 源码
1.首当其冲github 地址: https://github.com/casperjs