博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NOIP2018保卫王国
阅读量:5088 次
发布时间:2019-06-13

本文共 3608 字,大约阅读时间需要 12 分钟。

题目大意:给一颗有点权的树,每次规定两个点选还是不选,求这棵树的最小权点覆盖。

题解

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
#include
#define N 100009using namespace std;typedef long long ll;int tot,head[N],deep[N],p[N][20],n,m;char typef[5];ll dp[N][19][2][2],w[N],f[2][2],g[2][2],pr[N][2],lian[N][2],pr2[N][2];inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){
if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x;}struct node{
int n,to;}e[N<<1];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][0][0]=min(dp[x][l-1][0][1]+dp[y][l-1][1][0],dp[x][l-1][0][0]+dp[y][l-1][0][0]); dp[x][l][1][0]=min(dp[x][l-1][1][1]+dp[y][l-1][1][0],dp[x][l-1][1][0]+dp[y][l-1][0][0]); dp[x][l][0][1]=min(dp[x][l-1][0][1]+dp[y][l-1][1][1],dp[x][l-1][0][0]+dp[y][l-1][0][1]); dp[x][l][1][1]=min(dp[x][l-1][1][1]+dp[y][l-1][1][1],dp[x][l-1][1][0]+dp[y][l-1][0][1]);}void dfs(int u,int fa){ for(int i=1;(1<
<=deep[u];++i){ p[u][i]=p[p[u][i-1]][i-1]; hb(u,p[u][i-1],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]+1;p[v][0]=u; dp[v][0][0][1]=pr[u][1]-min(pr[v][1],pr[v][0]); dp[v][0][1][0]=pr[u][0]-pr[v][1]; dp[v][0][1][1]=pr[u][1]-min(pr[v][1],pr[v][0]); dfs(v,u); }}void predfs(int u,int fa){ pr[u][0]=0;pr[u][1]=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][0]+=pr[v][1];pr[u][1]+=min(pr[v][0],pr[v][1]); }}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][0]=lian[u][1]+pr[u][1]-min(pr[v][0],pr[v][1]); lian[v][1]=min(lian[v][0],lian[u][0]+pr[u][0]-pr[v][1]); dfs2(v,u); }}inline ll getlca(int a,int b,int x,int y){ if(deep[a]
=0;--i)if(deep[a]-(1<
=deep[b]){ f[now][1]=min(f[pre][0]+dp[a][i][0][1],f[pre][1]+dp[a][i][1][1]); f[now][0]=min(f[pre][0]+dp[a][i][0][0],f[pre][1]+dp[a][i][1][0]); swap(now,pre);a=p[a][i]; } if(a==b)return ans+f[pre][y]+lian[a][y]; g[pre][y]=0;ans+=pr[b][y];//cout<
<
=0;--i)if(p[a][i]!=p[b][i]){ f[now][1]=min(f[pre][0]+dp[a][i][0][1],f[pre][1]+dp[a][i][1][1]); f[now][0]=min(f[pre][0]+dp[a][i][0][0],f[pre][1]+dp[a][i][1][0]); g[now][1]=min(g[pre][0]+dp[b][i][0][1],g[pre][1]+dp[b][i][1][1]); g[now][0]=min(g[pre][0]+dp[b][i][0][0],g[pre][1]+dp[b][i][1][0]); swap(now,pre);a=p[a][i];b=p[b][i]; } swap(now,pre); ll ans1=f[now][1]+g[now][1]+pr[p[a][0]][0]-pr[a][1]-pr[b][1]; ll ans2=min(f[now][1],f[now][0])+min(g[now][0],g[now][1])+pr[p[a][0]][1]-min(pr[a][0],pr[a][1])-min(pr[b][0],pr[b][1]); return ans+min(ans1+lian[p[a][0]][0],ans2+lian[p[a][0]][1]);}int main(){ n=rd();m=rd();scanf("%s",typef);int u,v; for(int i=1;i<=n;++i)w[i]=rd(); for(int i=1;i<=n;++i) for(int j=0;j<=18;++j) for(int k=0;k<=1;++k)for(int l=0;l<=1;++l)dp[i][j][k][l]=1e12; for(int i=1;i
1e10)puts("-1");else printf("%lld\n",ans); } return 0;}

 

转载于:https://www.cnblogs.com/ZH-comld/p/10260557.html

你可能感兴趣的文章
开发安卓app配置
查看>>
Scala基础知识(二)
查看>>
Python:游戏:300行代码实现俄罗斯方块
查看>>
fedora22 无法联网的情况下rpm安装gcc5.1
查看>>
cocos2dx - 在MFC中使用cocos2dx
查看>>
网络通信协议之ICMP
查看>>
Oracle+Ado.Net(二)
查看>>
1048. Find Coins (25)
查看>>
1097. Deduplication on a Linked List (25)
查看>>
HIS系统结算后,没有更新单据状态为“已结算”
查看>>
java Comparator和Comparable(比较器)
查看>>
暗恋时最心酸的一刻
查看>>
myeclipse8.5安装axis2 1.3
查看>>
爪哇国新游记之二十六----迷宫寻路
查看>>
centos6.5安装supervisor
查看>>
R语言适配问题集锦
查看>>
map和string的使用方法
查看>>
PowerShell
查看>>
界面使用webview,并且webview里面有图片进行自动切换导致界面上滚动条卡顿。...
查看>>
从大公司做.NET 开发跳槽后来到小公司的做.NET移动端微信开发的个人感慨
查看>>