NOIP2018 保卫王国(动态DP)
题意
求最小权值点覆盖。
mmm次询问,每次给出两个点,分别要求每个点必须选或必须不选,输出每次的最小权值覆盖或者无解输出−1-1−1
题解
强制选或者不选可以看做修改权值为±∞\pm\infin±∞。
那么就是这道板题了。
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template<class T>inline void read(T &x) {
char ch; int flg=1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0'); x*=flg;
}
const int MAXN = 100005;
const LL INF = 1e10;
int n, m, fir[MAXN], nxt[MAXN<<1], to[MAXN<<1], cnt; LL V[MAXN];
inline void link(int u, int v) {
to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
}
int tmr, fa[MAXN], dfn[MAXN], tp[MAXN], bt[MAXN], son[MAXN], sz[MAXN], seq[MAXN];
struct mat {
LL a[2][2];
LL* operator[](int x) { return a[x]; }
mat operator*(const mat &o)const {
mat re;
for(int i = 0; i < 2; ++i)
for(int j = 0; j < 2; ++j)
re.a[i][j] = min(a[i][0]+o.a[0][j], a[i][1]+o.a[1][j]);
return re;
}
}t[MAXN<<2], val[MAXN];
void dfs1(int u, int ff) {
fa[u] = ff; sz[u] = 1;
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != ff) {
dfs1(v, u), sz[u] += sz[v];
(sz[v] > sz[son[u]]) && (son[u] = v);
}
}
LL f[MAXN][2];
void dfs2(int u, int top) {
tp[u] = top; bt[top] = u;
seq[dfn[u]=++tmr] = u;
if(son[u]) dfs2(son[u], top);
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != fa[u] && v != son[u])
dfs2(v, v);
}
void dp(int u) {
f[u][0] = V[u]; f[u][1] = 0;
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != fa[u])
dp(v),
f[u][0] += min(f[v][0], f[v][1]),
f[u][1] += f[v][0];
}
void build(int i, int l, int r) {
if(l == r) {
LL f0 = V[seq[l]], f1 = 0;
for(int j = fir[seq[l]], v; j; j = nxt[j])
if((v=to[j]) != fa[seq[l]] && v != son[seq[l]])
f0 += min(f[v][0], f[v][1]),
f1 += f[v][0];
val[l] = t[i] = (mat){ {{f0, f0} , {f1, INF}} };
return;
}
int mid = (l + r) >> 1;
build(i<<1, l, mid);
build(i<<1|1, mid+1, r);
t[i] = t[i<<1] * t[i<<1|1];
}
void update(int i, int l, int r, int x) {
if(l == r) { t[i] = val[l]; return; }
int mid = (l + r) >> 1;
if(x <= mid) update(i<<1, l, mid, x);
else update(i<<1|1, mid+1, r, x);
t[i] = t[i<<1] * t[i<<1|1];
}
mat query(int i, int l, int r, int x, int y) {
if(x == l && r == y) return t[i];
int mid = (l + r) >> 1;
if(y <= mid) return query(i<<1, l, mid, x, y);
if(x > mid) return query(i<<1|1, mid+1, r, x, y);
return query(i<<1, l, mid, x, mid) * query(i<<1|1, mid+1, r, mid+1, y);
}
void modify(int u, LL W) {
val[dfn[u]][0][0] += W-V[u];
val[dfn[u]][0][1] += W-V[u];
V[u]=W;
while(u) {
mat pre = query(1, 1, n, dfn[tp[u]], dfn[bt[tp[u]]]);
update(1, 1, n, dfn[u]);
mat now = query(1, 1, n, dfn[tp[u]], dfn[bt[tp[u]]]);
u = fa[tp[u]]; if(!u) return; int x = dfn[u];
LL p0 = pre[0][0], p1 = pre[1][0];
LL n0 = now[0][0], n1 = now[1][0];
val[x][0][0] = val[x][0][1] = val[x][0][0] + min(n0, n1) - min(p0, p1);
val[x][1][0] = val[x][1][0] + n0 - p0;
}
}
map<pair<int,int>, bool>E;
char s[10];
int main () {
read(n), read(m); scanf("%s", s);
for(int i = 1; i <= n; ++i) read(V[i]);
for(int i = 1, u, v; i < n; ++i) read(u), read(v), link(u, v), E[pair<int,int>(min(u,v), max(u,v))] = 1;
dfs1(1, 0), dfs2(1, 1), dp(1);
build(1, 1, n);
int a, x, b, y;
while(m--) {
read(a), read(x), read(b), read(y);
if(!x && !y && E.count(pair<int,int>(min(a,b), max(a,b)))) {
puts("-1"); continue;
}
LL sum = 0;
LL tmpa = V[a]; modify(a, V[a] + (x ? -INF : INF)); sum += (x ? -INF : 0);
LL tmpb = V[b]; modify(b, V[b] + (y ? -INF : INF)); sum += (y ? -INF : 0);
mat ans = query(1, 1, n, 1, dfn[bt[1]]);
printf("%lld\n", min(ans[0][0], ans[1][0])-sum);
modify(a, tmpa), modify(b, tmpb);
}
}
NOIP2018 保卫王国(动态DP)的更多相关文章
- luogu5024 [NOIp2018]保卫王国 (动态dp)
可以直接套动态dp,但因为它询问之间相互独立,所以可以直接倍增记x转移到fa[x]的矩阵 #include<bits/stdc++.h> #define CLR(a,x) memset(a ...
- BZOJ 5466: [Noip2018]保卫王国 动态DP
Code: // luogu-judger-enable-o2 #include<bits/stdc++.h> #define ll long long #define lson (now ...
- JZOJ5966. [NOIP2018TGD2T3] 保卫王国 (动态DP做法)
题目大意 这还不是人尽皆知? 有一棵树, 每个节点放军队的代价是\(a_i\), 一条边连接的两个点至少有一个要放军队, 还有\(q\)次询问, 每次规定其中的两个一定需要/不可放置军队, 问这样修改 ...
- 【NOIP2018】保卫王国 动态dp
此题场上打了一个正确的$44pts$,接着看错题疯狂$rush$“正确”的$44pts$,后来没$rush$完没将之前的代码$copy$回去,直接变零分了..... 这一题我们显然有一种$O(nm)$ ...
- luoguP5024 保卫王国 动态dp
题目大意: emmmmm 题解: QAQ #include <cstdio> #include <cstring> #include <iostream> usin ...
- LuoguP5024 保卫王国(动态DP,LCT)
最小权覆盖集 = 全集 - 最大权独立集 强制取点.不取点可以使用把权值改成正无穷或负无穷实现 接下来就是经典的"动态最大权独立集"了 O(nlogn). 这不是我说的,是immo ...
- P5024 保卫王国(动态dp/整体dp/倍增dp)
做法(倍增) 最好写的一种 以下0为不选,1为选 \(f_{i,0/1}\)为\(i\)子树的最小值,\(g_{i,0/1}\)为除i子树外的最小值 \(fh_{i,j,0/1,0/1}\)为确定\( ...
- 竞赛题解 - NOIP2018 保卫王国
\(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...
- [NOIP2018]保卫王国(树形dp+倍增)
我的倍增解法吊打动态 \(dp\) 全局平衡二叉树没学过 先讲 \(NOIP\) 范围内的倍增解法. 我们先考虑只有一个点取/不取怎么做. \(f[x][0/1]\) 表示取/不取 \(x\) 后,\ ...
- NOIP2018保卫王国
题目大意:给一颗有点权的树,每次规定两个点选还是不选,求这棵树的最小权点覆盖. 题解 ZZ码农题. 要用动态dp做,这题就是板子,然鹅并不会,留坑代填. 因为没有修改,所以可以静态倍增. 我们先做一遍 ...
随机推荐
- 025 Android 带进度条的对话框(ProgressDialog)
1.ProgressDialog介绍 ProgressDialog可以在当前界面弹出一个置顶于所有界面元素的对话框,同样具有屏蔽其他控件的交互能力,用于提示用户当前操作正在运行,让用户等待: 2.应用 ...
- [转帖]HAProxy 7层 负载均衡
HAProxy 7层 负载均衡 https://www.cnblogs.com/jicki/p/5546902.html HAProxy 系统 CentOS 5.8 x64 wget http://h ...
- IdentityServer4 学习二
进入identityserver4的官网:https://identityserver.io/ 找到文档 从overview下开始按照官方文档练习: 安装自定义模板 dotnet new -i Ide ...
- Python11之列表2(获取、删除列表元素、列表分片、拷贝)
一.获取列表元素值 列表名 [ 索引值 ] 注:索引值从0开始 nameList = ['詹姆斯','字母哥','乐福','威少','乔治','戴维斯'] nameList[0] '詹姆斯' name ...
- ES6语法基本使用
什么是ES6? ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了.Mozilla公司将在这个标准的基础上,推出JavaScript 2. ...
- vue 等比例截图组件,支持缩放和旋转
<template> <div class="crop-image" :style="wrapStyle"> <img :src= ...
- Generator 实现
Generator 是 ES6 中新增的语法,和 Promise 一样,都可以用来异步编程 // 使用 * 表示这是一个 Generator 函数 // 内部可以通过 yield 暂停代码 // 通过 ...
- 游记-NOI2019
Day -18 被各路julao们轮番吊打-- Day -12 鸽子F发布了笔试题库,然而并没有 "MLE全场记零分" 的操作 Day -8 广二体育馆机器装配完毕,误闯开幕式表演 ...
- 解决batik使用JScrollPane显示svg图滚动条不显示的问题
// 必须使用batik提供的JSVGScrollPane,使用swing自己的组件JScrollPane初始化时滚动条不会显示. JSVGScrollPane svgJScrollPane = ne ...
- js按钮频繁提交解决方案:
1.封装js: /// 函数节流 xhz.canRun = true; xhz.Throttling = function () { if (!xhz.canRun) { layer.msg('处理中 ...