「NOIP2018」保卫王国
「NOIP2018保卫王国」
题目描述
有一棵 \(n\) 个点, 点有点权 \(a_i\),\(m\) 组询问, 每次求钦点两个节点必须选或者必须不选后的树上最小点覆盖。\(1 \leq n, m \leq 10^5\)
解题思路 :
这个题唯一的意义恐怕是普及了一个还不能算太普及的科技,至少我没有时间去实现这个东西。当然 \(\text{nqiiii}\) 大爷考场上写了标算没写这个科技就过了是真的强。(不愧是机房里仅次于 \(\text{AK}\)王\(\text{zzd}\) 的男人)
我最早接触这个科技是联赛前一个星期 \(\text{txc}\) 让我膜他博客的时候接触到的,感觉他博客讲的非常优秀,现在这里挂一个链接传送一下:撩妹狂魔的博客
说普及科技的原因是因为这个题用动态\(\text{DP}\)来做基本就是一个模板题。首先不考虑询问,问题是一个简单的树形\(\text{DP}\) ,设 \(f[u][0/1]\) 表示以 \(u\) 为根的子树里面 \(u\) 不选的最小点覆盖。
\]
直接处理可能不太方便,不妨先考虑退化成一条 \(i \rightarrow i+1\) 的链的情况:
\]
考虑这个 \(\text{DP}\) 只有加法和取 \(\text{min}\) 操作,不妨用重新定义线性变换来描述这个转移:
0 & \infty \\
a_i & a_i
\end{bmatrix}
\begin{bmatrix}
f[i-1][0] \\
f[i-1][1]
\end{bmatrix}
=
\begin{bmatrix}
f[i][0] \\
f[i][1]
\end{bmatrix}
\]
这里把乘法重定义为加法,加法重定义为取 \(\min\),这个矩阵的乘法就等价于上式的转移。然后用线段树维护一下就可以做原题中链的部分分了。
考虑树的情况,既然会做链了,那么只需要树剖就能搞了。用线段树维护每一条重链上的转移,转移的时候需要将这个节点的轻儿子的贡献写到转移矩阵中,那么只需要先预处理出 \(f\) ,设:
B_u = a_u + \sum_{u\rightarrow v, v \neq mson} \min(f[v][1], f[v][1])
\]
原来的线性变换就改为:
A_u & \infty \\
B_u & B_u
\end{bmatrix}
\begin{bmatrix}
f[mson][0] \\
f[mson][1]
\end{bmatrix}
=
\begin{bmatrix}
f[u][0] \\
f[u][1]
\end{bmatrix}
\]
其中 \(mson\) 表示 \(u\) 的重儿子,此时每一个点的 \(f\) 就是其所在重链底部到它的所有矩阵乘起来的结果,用线段树维护即可。
考虑怎么回答这个题的询问,每次修改可以看做将两个 \(f[u][s]\) 修改为 \(\infty\) 后求答案,这里等价于修改 \(A_u\)或者\(B_u\) ,考虑一次修改的影响是到当前重链的链头的,所以每跳一次轻边都要重新计算父亲的 \(A_u\) 和 \(B_u\) ,这样相当于是在线段树上做单点修改,并求出修改完后 \(f[1]\) 的值。考虑轻边最多跳 \(log\) 次,修改的总复杂度是 \(O(log^2n)\),总复杂度是 \(O(nlog^2n)\)。
实际上这个东西还有两个 \(O(nlogn)\) 的做法,很显然其中一个是 \(\text{Lct}\),另外一个是叫全局平衡二叉树的科技,$\text{txc} $的博客里讲的非常优秀,大家可以去膜拜一波。
/*program by mangoyang*/
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
#define inf ((ll)(1e10))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 200005;
char str[10];
vector<int> ed[N];
ll f[N][2], g[N][2], ff[N], a[N];
int top[N], sz[N], ls[N], ms[N], dfn[N], n, m, cnt;
struct Matrix{
ll a[3][3];
inline Matrix(){
for(int i = 1; i <= 2; i++)
for(int j = 1; j <= 2; j++) a[i][j] = inf;
}
inline Matrix(ll x, ll y){
a[1][2] = x, a[2][1] = a[2][2] = y, a[1][1] = inf;
}
Matrix operator * (const Matrix &A) const{
Matrix c;
for(int i = 1; i <= 2; i++)
for(int j = 1; j <= 2; j++)
for(int k = 1; k <= 2; k++)
c.a[i][j] = Min(a[i][k] + A.a[k][j], c.a[i][j]);
return c;
}
};
struct SegmentTree{
Matrix s[N<<2];
#define lson (u << 1)
#define rson (u << 1 | 1)
inline void modify(int u, int l, int r, int pos, Matrix x){
if(l == r) return (void) (s[u] = x);
int mid = l + r >> 1;
if(pos <= mid) modify(lson, l, mid, pos, x);
else modify(rson, mid + 1, r, pos, x);
s[u] = s[lson] * s[rson];
}
inline Matrix query(int u, int l, int r, int L, int R){
if(l >= L && r <= R) return s[u];
int mid = l + r >> 1;
Matrix res;
res.a[1][1] = res.a[2][2] = 0, res.a[1][2] = res.a[2][1] = inf;
if(L <= mid) res = res * query(lson, l, mid, L, R);
if(mid < R) res = res * query(rson, mid + 1, r, L, R);
return res;
}
}Seg;
namespace gao{
inline void dfs(int u, int fa){
ff[u] = fa, sz[u] = 1, f[u][1] = a[u];
for(int i = 0; i < ed[u].size(); i++){
int v = ed[u][i];
if(v == fa) continue;
dfs(v, u), sz[u] += sz[v];
if(sz[v] > sz[ms[u]]) ms[u] = v;
f[u][0] += f[v][1];
f[u][1] += min(f[v][0], f[v][1]);
}
}
inline void dfs2(int u, int fa, int fff){
top[u] = fff, dfn[u] = ++cnt, g[u][1] = a[u];
if(!ms[u]){
Seg.modify(1, 1, n, dfn[u], Matrix(g[u][0], g[u][1]));
return (void) (ls[fff] = cnt);
}
dfs2(ms[u], u, fff);
for(int i = 0; i < ed[u].size(); i++){
int v = ed[u][i];
if(v == ms[u] || v == fa) continue;
g[u][0] += f[v][1];
g[u][1] += min(f[v][1], f[v][0]);
dfs2(v, u, v);
}
Seg.modify(1, 1, n, dfn[u], Matrix(g[u][0], g[u][1]));
}
inline ll update(int u){
Seg.modify(1, 1, n, dfn[u], Matrix(g[u][0], g[u][1]));
for(u = top[u]; u > 1; u = top[ff[u]]){
Matrix now = Seg.query(1, 1, n, dfn[u], ls[u]);
g[ff[u]][0] -= f[u][1];
g[ff[u]][1] -= Min(f[u][0], f[u][1]);
f[u][0] = now.a[1][2], f[u][1] = now.a[2][2];
g[ff[u]][0] += f[u][1];
g[ff[u]][1] += Min(f[u][0], f[u][1]);
Seg.modify(1, 1, n, dfn[ff[u]], Matrix(g[ff[u]][0], g[ff[u]][1]));
}
Matrix ans = Seg.query(1, 1, n, 1, ls[1]);
return min(ans.a[1][2], ans.a[2][2]);
}
}
signed main(){
read(n), read(m), scanf("%s", str);
for(int i = 1; i <= n; i++) read(a[i]);
for(int i = 1, x, y; i < n; i++){
read(x), read(y);
ed[x].push_back(y), ed[y].push_back(x);
}
gao::dfs(1, 0), gao::dfs2(1, 0, 1);
for(int i = 1, a, b, x, y; i <= m; i++){
read(a), read(x), read(b), read(y), x ^= 1, y ^= 1;
ll tmp1 = g[a][x], tmp2 = g[b][y];
g[a][x] = inf, gao::update(a);
g[b][y] = inf; ll ans = gao::update(b);
if(ans >= inf) puts("-1"); else printf("%lld\n", ans);
g[a][x] = tmp1, gao::update(a);
g[b][y] = tmp2, gao::update(b);
}
return 0;
}
「NOIP2018」保卫王国的更多相关文章
- loj 2955 「NOIP2018」保卫王国 - 树链剖分 - 动态规划
题目传送门 传送门 想抄一个短一点ddp板子.然后照着Jode抄,莫名其妙多了90行和1.3k. Code /** * loj * Problem#2955 * Accepted * Time: 26 ...
- 「题解」JOIOI 王国
「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...
- noip2018 d2t3 保卫王国 解题报告
保卫王国 电脑卡懒得把题面挪过来了. 朴素 \[ dp_{i,0}=\sum dp_{s,1}\\ dp_{i,1}=\sum \min(dp_{s,0},dp_{s,1})+p_i \] 然后直接动 ...
- 「NOIp2018」 游记
作为一个蒟蒻要去考tg了,心理还是有点慌的.初赛70,心惊胆战很长时间,后来降分到68了,居然卡线了(震惊……) $Day \ 0$ 今天请假在家复习了,打了几个数据结构模板.希望明天考场能++rp啊 ...
- 【NOIP2018】保卫王国 动态dp
此题场上打了一个正确的$44pts$,接着看错题疯狂$rush$“正确”的$44pts$,后来没$rush$完没将之前的代码$copy$回去,直接变零分了..... 这一题我们显然有一种$O(nm)$ ...
- 「洛谷5017」「NOIP2018」摆渡车【DP,经典好题】
前言 在考场被这个题搞自闭了,那个时候自己是真的太菜了.qwq 现在水平稍微高了一点,就过来切一下这一道\(DP\)经典好题. 附加一个题目链接:[洛谷] 正文 虽然题目非常的简短,但是解法有很多. ...
- @NOIP2018 - D2T3@ 保卫王国
目录 @题目描述@ @题解@ @代码@ @题目描述@ Z 国有n座城市,n−1 条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻 ...
- 「NOIP2018」赛道修建
传送门 Luogu 解题思路 一眼先二分(上界树的直径,下界最小边权),然后再考虑 \(\text{DP}\). 对于当前节点 \(u\),在它的所有儿子中分别返回一条匹配不完的长度最大的路径 \(M ...
- 「CTSC2006」歌唱王国
概率生成函数\(g(x)=\sum_{i\geq 0}t_ix^i\),\(t_i\)表示结果为\(i\)的概率 令\(f(x)\)表示i位表示串结束时长度为i的概率,\(G(x)\)表示i位表示串长 ...
随机推荐
- 使用 jQuery 避免鼠标双击
介绍 当用户双击DOM对象(例如按钮和链接等)时,对于用户交互一直是个麻烦的问题. 幸运的是, jQuery 提供了一个相当棒的解决方法. 那就是.one(). .one()这个方法是做什么的? 它附 ...
- Tool1—安装配置Windows Live Writer
详细步骤请看:http://home.cnblogs.com/group/topic/8550.html . Windows Live Writer手工配置步骤(在博客园配置时输入用户名与密码会自动完 ...
- 吐泡泡(2018年全国多校算法寒假训练营练习比赛(第二场)+栈模拟)+Plug-in(codeforces81A+栈模拟)
吐泡泡题目链接:https://www.nowcoder.com/acm/contest/74/A 题目: 思路: 这种题目当初卡了我很久,今天早训时遇到一个一样得题,一眼就想到用栈模拟,就又回来把这 ...
- 从urllib和urllib2基础到一个简单抓取网页图片的小爬虫
urllib最常用的两大功能(个人理解urllib用于辅助urllib2) 1.urllib.urlopen() 2. urllib.urlencode() #适当的编码,可用于后面的post提交 ...
- LOW逼三人组(三)----插入排序
插入排序思路 插入排序算法: import random # 随机模块 import time def cal_time(func): # 装饰器 ,用来检测算法所执行的时间 def wrapper( ...
- 常用的css3新特性总结
1:CSS3阴影 box-shadow的使用和技巧总结: 基本语法是{box-shadow:[inset] x-offset y-offset blur-radius spread-radiuscol ...
- Go语言 7 并发编程
文章由作者马志国在博客园的原创,若转载请于明显处标记出处:http://www.cnblogs.com/mazg/ Go学习群:415660935 今天我们学习Go语言编程的第七章,并发编程.语言级别 ...
- Java爬虫(二)
上一篇简单的实现了获取url返回的内容,在这一篇就要第返回的内容进行提取,并将结果保存到html中.而且这个爬虫是基于python爬虫的java语言实现,其逻辑大致相同. 一 . 需求: 抓取主页面: ...
- hdu 4605 Magic Ball Game (在线主席树/离线树状数组)
版权声明:本文为博主原创文章,未经博主允许不得转载. hdu 4605 题意: 有一颗树,根节点为1,每一个节点要么有两个子节点,要么没有,每个节点都有一个权值wi .然后,有一个球,附带值x . 球 ...
- C基础 如何让代码只执行一次
1.0 最简单, 最高效的方式 C 代码运行起点 main 就是个大单例函数. 如果把函数注册在其里面, 那么一定很可以 :) // 某个库需要初始化的函数 void log_init(void) { ...