题目大意:给一颗有点权的树,每次规定两个点选还是不选,求这棵树的最小权点覆盖。
题解
ZZ码农题。
要用动态dp做,这题就是板子,然鹅并不会,留坑代填。
因为没有修改,所以可以静态倍增。
我们先做一遍正常的树形dp,求出g[i][0/1],0/1表示当前节点选或不选。
然后我们再倒腾出一个数组l[i][0/1]表示从当前点作为根,再扣掉当前子树的答案。
然后倍增处理dp[i][j][0/1][0/1]表示从i向上2i长度的链,起点和终点的选择情况,表示以下区域的答案。
比如这条黑色的链,它表示的是黄圈里的所有点的答案。
然后对于一个询问,我们可以跳LCA,边跳变统计答案,这样我们就可以统计出以LCA为根的子树的答案,在加上之前处理过的l数组的答案,就可以吧答案算全了。
NOIP考这种****题有意思吗?
代码
#include<iostream>
#include<cstdio>
#define N 100009
using namespace std;
typedef long long ll;
int tot,head[N],deep[N],p[N][],n,m;
char typef[];
ll dp[N][][][],w[N],f[][],g[][],pr[N][],lian[N][],pr2[N][];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
struct node{int n,to;}e[N<<];
inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
inline void hb(int x,int y,int l){
dp[x][l][][]=min(dp[x][l-][][]+dp[y][l-][][],dp[x][l-][][]+dp[y][l-][][]);
dp[x][l][][]=min(dp[x][l-][][]+dp[y][l-][][],dp[x][l-][][]+dp[y][l-][][]);
dp[x][l][][]=min(dp[x][l-][][]+dp[y][l-][][],dp[x][l-][][]+dp[y][l-][][]);
dp[x][l][][]=min(dp[x][l-][][]+dp[y][l-][][],dp[x][l-][][]+dp[y][l-][][]);
}
void dfs(int u,int fa){
for(int i=;(<<i)<=deep[u];++i){
p[u][i]=p[p[u][i-]][i-];
hb(u,p[u][i-],i);
}
for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
int v=e[i].to;deep[v]=deep[u]+;p[v][]=u;
dp[v][][][]=pr[u][]-min(pr[v][],pr[v][]);
dp[v][][][]=pr[u][]-pr[v][];
dp[v][][][]=pr[u][]-min(pr[v][],pr[v][]);
dfs(v,u);
}
}
void predfs(int u,int fa){
pr[u][]=;pr[u][]=w[u];
for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
int v=e[i].to;predfs(v,u);
pr[u][]+=pr[v][];pr[u][]+=min(pr[v][],pr[v][]);
}
}
void dfs2(int u,int fa){
for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
int v=e[i].to;
// pr2[v][0]=pr2[u][1];pr2[v][1]=min(pr2[u][0],pr2[u][1]);
// lian[v][0]=pr2[v][0]-pr[v][0];lian[v][1]=pr2[v][1]-pr[v][1];
lian[v][]=lian[u][]+pr[u][]-min(pr[v][],pr[v][]);
lian[v][]=min(lian[v][],lian[u][]+pr[u][]-pr[v][]);
dfs2(v,u);
}
}
inline ll getlca(int a,int b,int x,int y){
if(deep[a]<deep[b])swap(a,b),swap(x,y);
// cout<<a<<" "<<b<<" "<<x<<" "<<y<<endl;
ll ans=pr[a][x]; //cout<<ans<<endl;
f[][x]=;int now=,pre=;
for(int i=;i>=;--i)if(deep[a]-(<<i)>=deep[b]){
f[now][]=min(f[pre][]+dp[a][i][][],f[pre][]+dp[a][i][][]);
f[now][]=min(f[pre][]+dp[a][i][][],f[pre][]+dp[a][i][][]);
swap(now,pre);a=p[a][i];
}
if(a==b)return ans+f[pre][y]+lian[a][y];
g[pre][y]=;ans+=pr[b][y];//cout<<ans<<endl;
for(int i=;i>=;--i)if(p[a][i]!=p[b][i]){
f[now][]=min(f[pre][]+dp[a][i][][],f[pre][]+dp[a][i][][]);
f[now][]=min(f[pre][]+dp[a][i][][],f[pre][]+dp[a][i][][]);
g[now][]=min(g[pre][]+dp[b][i][][],g[pre][]+dp[b][i][][]);
g[now][]=min(g[pre][]+dp[b][i][][],g[pre][]+dp[b][i][][]);
swap(now,pre);a=p[a][i];b=p[b][i];
}
swap(now,pre);
ll ans1=f[now][]+g[now][]+pr[p[a][]][]-pr[a][]-pr[b][];
ll ans2=min(f[now][],f[now][])+min(g[now][],g[now][])+pr[p[a][]][]-min(pr[a][],pr[a][])-min(pr[b][],pr[b][]);
return ans+min(ans1+lian[p[a][]][],ans2+lian[p[a][]][]);
}
int main(){
n=rd();m=rd();scanf("%s",typef);int u,v;
for(int i=;i<=n;++i)w[i]=rd();
for(int i=;i<=n;++i)
for(int j=;j<=;++j)
for(int k=;k<=;++k)for(int l=;l<=;++l)dp[i][j][k][l]=1e12;
for(int i=;i<n;++i){u=rd();v=rd();add(u,v);add(v,u);}
predfs(,);
pr2[][]=pr[][];pr2[][]=pr[][];dfs2(,);
dfs(,);int a,x,b,y;
/* for(int i=1;i<=n;++i){
cout<<i<<" ";
for(int j=0;j<=1;++j)cout<<lian[i][j]<<" ";cout<<endl;
}*/
/* for(int i=1;i<=n;++i){
cout<<i<<endl;
for(int j=0;(1<<j)<=deep[i];++j)cout<<dp[i][j][0][0]<<" "<<dp[i][j][0][1]<<" "<<dp[i][j][1][0]<<" "<<dp[i][j][1][1]<<endl;
}*/
while(m--){
a=rd();x=rd();b=rd();y=rd();
for(int i=;i<=;++i)for(int j=;j<=;++j)f[i][j]=g[i][j]=1e12;
ll ans=getlca(a,b,x,y);
if(ans>1e10)puts("-1");else printf("%lld\n",ans);
}
return ;
}
NOIP2018保卫王国的更多相关文章
-
竞赛题解 - NOIP2018 保卫王国
\(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...
-
[NOIP2018]保卫王国 题解
NOIP2018提高组D2T3 ddp虽然好想,但是码量有点大(其实是我不会),因此本文用倍增优化树形DP来解决本题. 题意分析 给一棵树染色,每个节点染色需要一定的花费,要求相邻两个节点至少要有一个 ...
-
【比赛】NOIP2018 保卫王国
DDP模板题 #include<bits/stdc++.h> #define ui unsigned int #define ll long long #define db double ...
-
luogu5024 [NOIp2018]保卫王国 (动态dp)
可以直接套动态dp,但因为它询问之间相互独立,所以可以直接倍增记x转移到fa[x]的矩阵 #include<bits/stdc++.h> #define CLR(a,x) memset(a ...
-
2019.02.16 bzoj5466: [Noip2018]保卫王国(链分治+ddp)
传送门 题意简述: mmm次询问,每次规定两个点必须选或者不选,求树上的带权最小覆盖. 思路: 考虑链分治+ddpddpddp 仍然是熟悉的套路,先考虑没有修改的状态和转移: 令fi,0/1f_{i, ...
-
[NOIP2018]保卫王国
嘟嘟嘟 由于一些知道的人所知道的,不知道的人所不知道的原因,我来发NOIP2018day2T3的题解了. (好像我只是个搬运工--) 这题真可以叫做NOIplus了,跟其他几道比较水的题果然不一样,无 ...
-
[NOIP2018]保卫王国(树形dp+倍增)
我的倍增解法吊打动态 \(dp\) 全局平衡二叉树没学过 先讲 \(NOIP\) 范围内的倍增解法. 我们先考虑只有一个点取/不取怎么做. \(f[x][0/1]\) 表示取/不取 \(x\) 后,\ ...
-
「NOIP2018 保卫王国」
题目 强制选点我们可以把那个点权搞成\(-inf\),强制不选我们搞成\(inf\),之后就真的成为动态\(dp\)的板子题了 由于不想像板子那样再写一个最大独立集的方程,之后利用最小点覆盖=总点权- ...
-
BZOJ5466 NOIP2018保卫王国(倍增+树形dp)
暴力dp非常显然,设f[i][0/1]表示i号点不选/选时i子树内的答案,则f[i][0]=Σf[son][1],f[i][1]=a[i]+Σmin(f[son][0],f[son][1]). 注意到 ...
随机推荐
-
xamarin UWP平台下 HUD 自定义弹窗
在我的上一篇博客中我写了一个在xamarin的UWP平台下的自定义弹窗控件.在上篇文章中介绍了一种弹窗的写法,但在实际应用中发现了该方法的不足: 1.当弹窗出现后,我们拖动整个窗口大小的时候,弹窗的窗 ...
-
android EditText inputType说明
在开发的过程中,通常会用到EditText,如何让虚拟键盘来适应输入框中内容的类型,通常我们都会在xml文件中加入android:inputType="". android:inp ...
-
Python【基础第四篇】
一.迭代器(iterator) 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退. ...
-
[Linked List]Delete Node in a Linked List
otal Accepted: 48115 Total Submissions: 109291 Difficulty: Easy Write a function to delete a node (e ...
-
10个JavaScript小技巧
1.变量转换 看起来很简单,但据我所看到的,使用构造函数,像Array()或者Number()来进行变量转换是常用的做法.始终使用原始数据类型(有时也称为字面量)来转换变量,这种没有任何额外的影响的做 ...
-
python基础6 迭代器 生成器
可迭代的:内部含有__iter__方法的数据类型叫可迭代的,也叫迭代对象实现了迭代协议的对象 运用dir()方法来测试一个数据类型是不是可迭代的的. 迭代器协议是指:对象需要提供next方法,它要么返 ...
-
springboot学习随笔(一):springboot环境构建:eclipse+maven+jdk1.8
一:所需环境 1.jdk1.8(配置环境变量,可自行搜索相关文档) 2.maven(maven的配置不在赘述,可自行搜索相关文档) 3.eclipse(第三种方式,eclipse集成sts时需要,直接 ...
-
小程序问题集:保存失败:Error: ENOENT: no such file or directory, open
问题如图: 当编译的时候 会提示找不到这个文件(index),但是确信项目目录里已经删除了该页面路径,并且app.json的pages列表中也没有该页面: 这时候需要看一下当前已经打开的文件中是否 ...
-
SDOI2014 R1做题笔记
SDOI2014 R1做题笔记 经过很久很久的时间,shzr又做完了SDOI2014一轮的题目. 但是我不想写做题笔记(
-
ASP.NET MVC必须知道的那些事!
MVC的由来: 在MVC模式之前,View界面的呈现.用户交互操作的捕捉与相应.业务流程的执行以及数据的存储等都是在一起的,这种设计模式叫自治视图. 这重设计模式主要存在三大弊端: 重用性:业务逻辑与 ...